@sentry/server-utils
Advanced tools
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const channels = require('../../orchestrion/channels.js'); | ||
| const tracingChannel = require('../../tracing-channel.js'); | ||
| const INTEGRATION_NAME = "Anthropic_AI"; | ||
| const ORIGIN = "auto.ai.orchestrion.anthropic"; | ||
| const INSTRUMENTED_CHANNELS = [ | ||
| { channel: channels.CHANNELS.ANTHROPIC_CHAT, operation: "chat", methodPath: "messages.create", stream: "async-iterable" }, | ||
| { channel: channels.CHANNELS.ANTHROPIC_MODELS, operation: "models", methodPath: "models.retrieve", stream: "none" }, | ||
| { | ||
| channel: channels.CHANNELS.ANTHROPIC_MESSAGES_STREAM, | ||
| operation: "chat", | ||
| methodPath: "messages.stream", | ||
| stream: "message-stream" | ||
| } | ||
| ]; | ||
| let subscribed = false; | ||
| const _anthropicChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel || subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| core.waitForTracingChannelBinding(() => { | ||
| for (const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS) { | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:anthropic] subscribing to channel "${channel}"`); | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channel), | ||
| (data) => createGenAiSpan(data, operation, methodPath, options), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| core.addAnthropicResponseAttributes( | ||
| span, | ||
| data.result, | ||
| core.resolveAIRecordingOptions(options).recordOutputs | ||
| ); | ||
| }, | ||
| deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, stream, options) | ||
| } | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function createGenAiSpan(data, operation, methodPath, options) { | ||
| const args = data.arguments ?? []; | ||
| if (core._INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) { | ||
| return void 0; | ||
| } | ||
| const requestOptions = args[1]; | ||
| if (requestOptions?.headers?.["X-Stainless-Helper-Method"] === "stream") { | ||
| return void 0; | ||
| } | ||
| const params = typeof args[0] === "object" && args[0] !== null ? args[0] : void 0; | ||
| const { recordInputs } = core.resolveAIRecordingOptions(options); | ||
| const enableTruncation = core.shouldEnableTruncation(options.enableTruncation); | ||
| const attributes = core.extractAnthropicRequestAttributes(args, methodPath, operation); | ||
| const model = attributes[core.GEN_AI_REQUEST_MODEL_ATTRIBUTE] || "unknown"; | ||
| attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN; | ||
| const span = core.startInactiveSpan({ | ||
| name: `${operation} ${model}`, | ||
| op: `gen_ai.${operation}`, | ||
| attributes | ||
| }); | ||
| if (recordInputs && params) { | ||
| core.addAnthropicRequestAttributes(span, params, enableTruncation); | ||
| } | ||
| return span; | ||
| } | ||
| function isAsyncIterable(value) { | ||
| return !!value && typeof value[Symbol.asyncIterator] === "function"; | ||
| } | ||
| function isMessageStream(value) { | ||
| return !!value && typeof value.on === "function"; | ||
| } | ||
| function wrapStreamResult(span, data, stream, options) { | ||
| const { recordOutputs } = core.resolveAIRecordingOptions(options); | ||
| const result = data.result; | ||
| if (stream === "async-iterable" && isAsyncIterable(result)) { | ||
| const iterate = result[Symbol.asyncIterator].bind(result); | ||
| const instrumented = core.instrumentAsyncIterableStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs); | ||
| result[Symbol.asyncIterator] = () => instrumented; | ||
| return true; | ||
| } | ||
| if (stream === "message-stream" && isMessageStream(result)) { | ||
| core.instrumentMessageStream(result, span, recordOutputs); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| const anthropicChannelIntegration = core.defineIntegration(_anthropicChannelIntegration); | ||
| exports.anthropicChannelIntegration = anthropicChannelIntegration; | ||
| //# sourceMappingURL=anthropic.js.map |
| {"version":3,"file":"anthropic.js","sources":["../../../../src/integrations/tracing-channel/anthropic.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { AnthropicAiOptions, AnthropicAiResponse, IntegrationFn, Span, SpanAttributeValue } from '@sentry/core';\nimport {\n _INTERNAL_shouldSkipAiProviderWrapping,\n addAnthropicRequestAttributes,\n addAnthropicResponseAttributes,\n debug,\n defineIntegration,\n extractAnthropicRequestAttributes,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n instrumentAsyncIterableStream,\n instrumentMessageStream,\n resolveAIRecordingOptions,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Same name as the OTel integration by design: when enabled, the OTel 'Anthropic_AI'\n// integration is dropped from the default set (see the Node opt-in loader).\nconst INTEGRATION_NAME = 'Anthropic_AI' as const;\n\n// Distinct from the proxy's `auto.ai.anthropic` so spans from the orchestrion path\n// are attributable separately from the OTel/proxy one.\nconst ORIGIN = 'auto.ai.orchestrion.anthropic';\n\n// `stream` determines how the span is ended\nconst INSTRUMENTED_CHANNELS = [\n { channel: CHANNELS.ANTHROPIC_CHAT, operation: 'chat', methodPath: 'messages.create', stream: 'async-iterable' },\n { channel: CHANNELS.ANTHROPIC_MODELS, operation: 'models', methodPath: 'models.retrieve', stream: 'none' },\n {\n channel: CHANNELS.ANTHROPIC_MESSAGES_STREAM,\n operation: 'chat',\n methodPath: 'messages.stream',\n stream: 'message-stream',\n },\n] as const;\n\ntype StreamMode = (typeof INSTRUMENTED_CHANNELS)[number]['stream'];\n\ninterface AnthropicChannelContext {\n arguments: unknown[];\n result?: unknown;\n}\n\nlet subscribed = false;\n\nconst _anthropicChannelIntegration = ((options: AnthropicAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // tracingChannel is unavailable before Node 18.19 and prevent double-subscribe\n if (!diagnosticsChannel.tracingChannel || subscribed) {\n return;\n }\n subscribed = true;\n\n // `bindTracingChannelToSpan` needs the async-context binding that `initOpenTelemetry()` registers\n // after `setupOnce` runs, so wait for it before subscribing.\n waitForTracingChannelBinding(() => {\n for (const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS) {\n DEBUG_BUILD && debug.log(`[orchestrion:anthropic] subscribing to channel \"${channel}\"`);\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<AnthropicChannelContext>(channel),\n data => createGenAiSpan(data, operation, methodPath, options),\n {\n beforeSpanEnd: (span, data) => {\n addAnthropicResponseAttributes(\n span,\n data.result as AnthropicAiResponse,\n resolveAIRecordingOptions(options).recordOutputs,\n );\n },\n deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, stream, options),\n },\n );\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Build the span for an instrumented call.\n * Returning `undefined` opts the payload out so no span is opened.\n */\nfunction createGenAiSpan(\n data: AnthropicChannelContext,\n operation: string,\n methodPath: string,\n options: AnthropicAiOptions,\n): Span | undefined {\n const args = data.arguments ?? [];\n\n // When LangChain (or another provider) is driving the SDK, it records the spans itself and marks this\n // provider as skipped — mirror the OTel integration and don't double-instrument.\n if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) {\n return undefined;\n }\n\n // `messages.stream()` internally calls the instrumented `messages.create({ stream: true })` tagged with\n // an `X-Stainless-Helper-Method: 'stream'` header. The messages-stream channel already covers it, so skip\n // the nested create to avoid a duplicate span.\n const requestOptions = args[1] as { headers?: Record<string, unknown> } | undefined;\n if (requestOptions?.headers?.['X-Stainless-Helper-Method'] === 'stream') {\n return undefined;\n }\n\n const params = typeof args[0] === 'object' && args[0] !== null ? (args[0] as Record<string, unknown>) : undefined;\n\n const { recordInputs } = resolveAIRecordingOptions(options);\n const enableTruncation = shouldEnableTruncation(options.enableTruncation);\n\n const attributes = extractAnthropicRequestAttributes(args, methodPath, operation);\n const model = (attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN;\n\n const span = startInactiveSpan({\n name: `${operation} ${model}`,\n op: `gen_ai.${operation}`,\n attributes: attributes as Record<string, SpanAttributeValue>,\n });\n\n if (recordInputs && params) {\n addAnthropicRequestAttributes(span, params, enableTruncation);\n }\n\n return span;\n}\n\ntype AsyncIterableStream = { [Symbol.asyncIterator]: () => AsyncIterator<unknown> };\ntype MessageStreamEmitter = { on: (...args: unknown[]) => void };\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterableStream {\n return !!value && typeof (value as AsyncIterableStream)[Symbol.asyncIterator] === 'function';\n}\n\nfunction isMessageStream(value: unknown): value is MessageStreamEmitter {\n return !!value && typeof (value as MessageStreamEmitter).on === 'function';\n}\n\n/**\n * Hand span-ending ownership to a streamed result: returns `true` to skip the normal `beforeSpanEnd`,\n * `false` for non-streaming results (which end via `beforeSpanEnd`).\n *\n * - `async-iterable`: patch the `Stream`'s async iterator in place so `instrumentAsyncIterableStream` ends\n * the span when iteration finishes.\n * - `message-stream`: `instrumentMessageStream` attaches `'message'`/`'error'` listeners that end the span.\n */\nfunction wrapStreamResult(\n span: Span,\n data: AnthropicChannelContext,\n stream: StreamMode,\n options: AnthropicAiOptions,\n): boolean {\n const { recordOutputs } = resolveAIRecordingOptions(options);\n const result = data.result;\n\n if (stream === 'async-iterable' && isAsyncIterable(result)) {\n const iterate = result[Symbol.asyncIterator].bind(result);\n const instrumented = instrumentAsyncIterableStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs);\n result[Symbol.asyncIterator] = () => instrumented;\n return true;\n }\n\n if (stream === 'message-stream' && isMessageStream(result)) {\n instrumentMessageStream(result, span, recordOutputs);\n return true;\n }\n\n return false;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven Anthropic integration. Subscribes to the `orchestrion:@anthropic-ai/sdk:*`\n * diagnostics_channels injected into the SDK's chat (`messages`/`completions`/beta `messages`), `models`, and\n * `messages.stream()` methods, so it requires the orchestrion runtime hook or bundler plugin.\n */\nexport const anthropicChannelIntegration = defineIntegration(_anthropicChannelIntegration);\n"],"names":["CHANNELS","waitForTracingChannelBinding","DEBUG_BUILD","debug","bindTracingChannelToSpan","addAnthropicResponseAttributes","resolveAIRecordingOptions","_INTERNAL_shouldSkipAiProviderWrapping","shouldEnableTruncation","extractAnthropicRequestAttributes","GEN_AI_REQUEST_MODEL_ATTRIBUTE","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startInactiveSpan","addAnthropicRequestAttributes","instrumentAsyncIterableStream","instrumentMessageStream","defineIntegration"],"mappings":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const LIFECYCLE_EXT_POINTS = [ | ||
| "onPreAuth", | ||
| "onCredentials", | ||
| "onPostAuth", | ||
| "onPreHandler", | ||
| "onPostHandler", | ||
| "onPreResponse", | ||
| "onRequest" | ||
| ]; | ||
| const handlerPatched = /* @__PURE__ */ Symbol("hapi-handler-patched"); | ||
| const HapiLayerType = { | ||
| ROUTER: "router", | ||
| PLUGIN: "plugin", | ||
| EXT: "server.ext" | ||
| }; | ||
| const HapiLifecycleMethodNames = new Set(LIFECYCLE_EXT_POINTS); | ||
| var AttributeNames = /* @__PURE__ */ ((AttributeNames2) => { | ||
| AttributeNames2["HAPI_TYPE"] = "hapi.type"; | ||
| AttributeNames2["PLUGIN_NAME"] = "hapi.plugin.name"; | ||
| AttributeNames2["EXT_TYPE"] = "server.ext.type"; | ||
| return AttributeNames2; | ||
| })(AttributeNames || {}); | ||
| exports.AttributeNames = AttributeNames; | ||
| exports.HapiLayerType = HapiLayerType; | ||
| exports.HapiLifecycleMethodNames = HapiLifecycleMethodNames; | ||
| exports.handlerPatched = handlerPatched; | ||
| //# sourceMappingURL=hapi-types.js.map |
| {"version":3,"file":"hapi-types.js","sources":["../../../../src/integrations/tracing-channel/hapi-types.ts"],"sourcesContent":["/*\n * Structural type definitions and constants ported from the vendored\n * `@opentelemetry/instrumentation-hapi` types, with all `@hapi/*` and\n * `@opentelemetry/*` dependencies removed. Only the shapes actually accessed by\n * the orchestrion hapi subscriber are kept.\n */\n\n// Single source of truth for the request lifecycle extension points, so the\n// `ServerRequestExtType` union and the runtime `HapiLifecycleMethodNames` set\n// below can't drift apart.\nconst LIFECYCLE_EXT_POINTS = [\n 'onPreAuth',\n 'onCredentials',\n 'onPostAuth',\n 'onPreHandler',\n 'onPostHandler',\n 'onPreResponse',\n 'onRequest',\n] as const;\n\nexport type ServerRequestExtType = (typeof LIFECYCLE_EXT_POINTS)[number];\n\nexport type LifecycleMethod = (request: unknown, h: unknown, err?: Error) => unknown;\n\nexport interface ServerRouteOptions {\n handler?: LifecycleMethod | unknown;\n [key: string]: unknown;\n}\n\nexport interface ServerRoute {\n path: string;\n method: string;\n handler?: LifecycleMethod | unknown;\n options?: ((server: unknown) => ServerRouteOptions) | ServerRouteOptions;\n [key: string]: unknown;\n}\n\nexport interface ServerExtEventsObject {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface ServerExtEventsRequestObject {\n type: ServerRequestExtType;\n method: LifecycleMethod;\n [key: string]: unknown;\n}\n\nexport interface ServerExtOptions {\n [key: string]: unknown;\n}\n\n/**\n * This symbol is used to mark a Hapi route handler or server extension handler as\n * already patched, since it's possible to use these handlers multiple times\n * i.e. when allowing multiple versions of one plugin, or when registering a plugin\n * multiple times on different servers.\n */\nexport const handlerPatched: unique symbol = Symbol('hapi-handler-patched');\n\nexport type PatchableServerRoute = ServerRoute & {\n [handlerPatched]?: boolean;\n};\n\nexport type PatchableExtMethod = LifecycleMethod & {\n [handlerPatched]?: boolean;\n};\n\nexport type ServerExtDirectInput = [ServerRequestExtType, LifecycleMethod, (ServerExtOptions | undefined)?];\n\nexport const HapiLayerType = {\n ROUTER: 'router',\n PLUGIN: 'plugin',\n EXT: 'server.ext',\n} as const;\n\nexport const HapiLifecycleMethodNames = new Set<string>(LIFECYCLE_EXT_POINTS);\n\nexport enum AttributeNames {\n HAPI_TYPE = 'hapi.type',\n PLUGIN_NAME = 'hapi.plugin.name',\n EXT_TYPE = 'server.ext.type',\n}\n"],"names":["AttributeNames"],"mappings":";;AAUA,MAAM,oBAAA,GAAuB;AAAA,EAC3B,WAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAA;AAwCO,MAAM,cAAA,0BAAuC,sBAAsB;AAYnE,MAAM,aAAA,GAAgB;AAAA,EAC3B,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,GAAA,EAAK;AACP;AAEO,MAAM,wBAAA,GAA2B,IAAI,GAAA,CAAY,oBAAoB;AAErE,IAAK,cAAA,qBAAAA,eAAAA,KAAL;AACL,EAAAA,gBAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,gBAAA,aAAA,CAAA,GAAc,kBAAA;AACd,EAAAA,gBAAA,UAAA,CAAA,GAAW,iBAAA;AAHD,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;;;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const core = require('@sentry/core'); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
| const hapiTypes = require('./hapi-types.js'); | ||
| function setHttpServerSpanRouteAttribute(route) { | ||
| const activeSpan = core.getActiveSpan(); | ||
| if (!activeSpan) { | ||
| return; | ||
| } | ||
| const rootSpan = core.getRootSpan(activeSpan); | ||
| if (!rootSpan) { | ||
| return; | ||
| } | ||
| if (core.spanToJSON(rootSpan).data[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] !== "http.server") { | ||
| return; | ||
| } | ||
| rootSpan.setAttribute(attributes.HTTP_ROUTE, route); | ||
| } | ||
| const isLifecycleExtType = (variableToCheck) => { | ||
| return typeof variableToCheck === "string" && hapiTypes.HapiLifecycleMethodNames.has(variableToCheck); | ||
| }; | ||
| const isLifecycleExtEventObj = (variableToCheck) => { | ||
| const event = variableToCheck?.type; | ||
| return event !== void 0 && isLifecycleExtType(event); | ||
| }; | ||
| const isDirectExtInput = (variableToCheck) => { | ||
| return Array.isArray(variableToCheck) && variableToCheck.length <= 3 && isLifecycleExtType(variableToCheck[0]) && typeof variableToCheck[1] === "function"; | ||
| }; | ||
| const isPatchableExtMethod = (variableToCheck) => { | ||
| return !Array.isArray(variableToCheck); | ||
| }; | ||
| const getRouteMetadata = (route, pluginName) => { | ||
| const attributes$1 = { | ||
| [attributes.HTTP_ROUTE]: route.path, | ||
| // eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes | ||
| [attributes.HTTP_METHOD]: route.method | ||
| }; | ||
| let name; | ||
| if (pluginName) { | ||
| attributes$1[hapiTypes.AttributeNames.HAPI_TYPE] = hapiTypes.HapiLayerType.PLUGIN; | ||
| attributes$1[hapiTypes.AttributeNames.PLUGIN_NAME] = pluginName; | ||
| name = `${pluginName}: route - ${route.path}`; | ||
| } else { | ||
| attributes$1[hapiTypes.AttributeNames.HAPI_TYPE] = hapiTypes.HapiLayerType.ROUTER; | ||
| name = `route - ${route.path}`; | ||
| } | ||
| return { attributes: attributes$1, name }; | ||
| }; | ||
| const getExtMetadata = (extPoint, pluginName, methodName) => { | ||
| let baseName = `ext - ${extPoint}`; | ||
| if (methodName && methodName !== "method") { | ||
| baseName = `ext - ${extPoint} - ${methodName}`; | ||
| } | ||
| if (pluginName) { | ||
| return { | ||
| attributes: { | ||
| [hapiTypes.AttributeNames.EXT_TYPE]: extPoint, | ||
| [hapiTypes.AttributeNames.HAPI_TYPE]: hapiTypes.HapiLayerType.EXT, | ||
| [hapiTypes.AttributeNames.PLUGIN_NAME]: pluginName | ||
| }, | ||
| name: `${pluginName}: ${baseName}` | ||
| }; | ||
| } | ||
| return { | ||
| attributes: { | ||
| [hapiTypes.AttributeNames.EXT_TYPE]: extPoint, | ||
| [hapiTypes.AttributeNames.HAPI_TYPE]: hapiTypes.HapiLayerType.EXT | ||
| }, | ||
| name: baseName | ||
| }; | ||
| }; | ||
| function startMetadataSpan(metadata, original) { | ||
| return core.startSpan( | ||
| { | ||
| name: metadata.name, | ||
| op: `${metadata.attributes[hapiTypes.AttributeNames.HAPI_TYPE]}.hapi`, | ||
| attributes: { | ||
| ...metadata.attributes, | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.orchestrion.hapi" | ||
| } | ||
| }, | ||
| original | ||
| ); | ||
| } | ||
| function wrapRouteHandler(route, pluginName) { | ||
| if (route[hapiTypes.handlerPatched] === true) return route; | ||
| route[hapiTypes.handlerPatched] = true; | ||
| const wrapHandler = (oldHandler) => { | ||
| return function(...params) { | ||
| if (!core.getActiveSpan()) { | ||
| return oldHandler.call(this, ...params); | ||
| } | ||
| setHttpServerSpanRouteAttribute(route.path); | ||
| const metadata = getRouteMetadata(route, pluginName); | ||
| return startMetadataSpan(metadata, () => oldHandler.call(this, ...params)); | ||
| }; | ||
| }; | ||
| if (typeof route.handler === "function") { | ||
| route.handler = wrapHandler(route.handler); | ||
| } else if (typeof route.options === "function") { | ||
| const oldOptions = route.options; | ||
| route.options = function(server) { | ||
| const options = oldOptions(server); | ||
| if (typeof options.handler === "function") { | ||
| options.handler = wrapHandler(options.handler); | ||
| } | ||
| return options; | ||
| }; | ||
| } else if (typeof route.options?.handler === "function") { | ||
| route.options.handler = wrapHandler(route.options.handler); | ||
| } | ||
| return route; | ||
| } | ||
| function wrapExtMethods(method, extPoint, pluginName) { | ||
| if (Array.isArray(method)) { | ||
| for (let i = 0; i < method.length; i++) { | ||
| method[i] = wrapExtMethods(method[i], extPoint); | ||
| } | ||
| return method; | ||
| } else if (isPatchableExtMethod(method)) { | ||
| if (method[hapiTypes.handlerPatched] === true) return method; | ||
| method[hapiTypes.handlerPatched] = true; | ||
| const newHandler = function(...params) { | ||
| if (!core.getActiveSpan()) { | ||
| return method.apply(this, params); | ||
| } | ||
| const metadata = getExtMetadata(extPoint, pluginName, method.name); | ||
| return startMetadataSpan(metadata, () => method.apply(void 0, params)); | ||
| }; | ||
| newHandler[hapiTypes.handlerPatched] = true; | ||
| return newHandler; | ||
| } | ||
| return method; | ||
| } | ||
| function wrapRouteArguments(args, pluginName) { | ||
| const route = args[0]; | ||
| if (Array.isArray(route)) { | ||
| for (let i = 0; i < route.length; i++) { | ||
| route[i] = wrapRouteHandler(route[i], pluginName); | ||
| } | ||
| } else { | ||
| args[0] = wrapRouteHandler(route, pluginName); | ||
| } | ||
| } | ||
| function wrapExtArguments(args, pluginName) { | ||
| if (Array.isArray(args[0])) { | ||
| const eventsList = args[0]; | ||
| for (let i = 0; i < eventsList.length; i++) { | ||
| const eventObj = eventsList[i]; | ||
| if (isLifecycleExtType(eventObj.type)) { | ||
| const lifecycleEventObj = eventObj; | ||
| const handler = wrapExtMethods(lifecycleEventObj.method, eventObj.type, pluginName); | ||
| lifecycleEventObj.method = handler; | ||
| eventsList[i] = lifecycleEventObj; | ||
| } | ||
| } | ||
| return; | ||
| } else if (isDirectExtInput(args)) { | ||
| const extInput = args; | ||
| const method = extInput[1]; | ||
| const handler = wrapExtMethods(method, extInput[0], pluginName); | ||
| args[1] = handler; | ||
| return; | ||
| } else if (isLifecycleExtEventObj(args[0])) { | ||
| const lifecycleEventObj = args[0]; | ||
| const handler = wrapExtMethods(lifecycleEventObj.method, lifecycleEventObj.type, pluginName); | ||
| lifecycleEventObj.method = handler; | ||
| } | ||
| } | ||
| exports.getExtMetadata = getExtMetadata; | ||
| exports.getRouteMetadata = getRouteMetadata; | ||
| exports.wrapExtArguments = wrapExtArguments; | ||
| exports.wrapRouteArguments = wrapRouteArguments; | ||
| //# sourceMappingURL=hapi-utils.js.map |
| {"version":3,"file":"hapi-utils.js","sources":["../../../../src/integrations/tracing-channel/hapi-utils.ts"],"sourcesContent":["/*\n * OTel-free, `@hapi/*`-free port of the span-building helpers and handler/ext\n * wrap logic from the vendored `@opentelemetry/instrumentation-hapi`\n * (upstream @opentelemetry/instrumentation-hapi@0.64.0). Span output (names,\n * ops, origins, attributes) is kept byte-identical to that instrumentation;\n * span creation goes through the `@sentry/core` API and the OTel active-span\n * guard is replaced with `getActiveSpan()`.\n */\n\nimport {\n getActiveSpan,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n startSpan,\n} from '@sentry/core';\nimport type {\n LifecycleMethod,\n PatchableExtMethod,\n PatchableServerRoute,\n ServerExtDirectInput,\n ServerExtEventsObject,\n ServerExtEventsRequestObject,\n ServerRequestExtType,\n ServerRoute,\n ServerRouteOptions,\n} from './hapi-types';\n// eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes\nimport { HTTP_METHOD, HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport { AttributeNames, handlerPatched, HapiLayerType, HapiLifecycleMethodNames } from './hapi-types';\n\ntype SpanAttributes = Record<string, string | undefined>;\n\ninterface SpanMetadata {\n attributes: SpanAttributes;\n name: string;\n}\n\n/**\n * Set the `http.route` attribute on the root HTTP server span for the current trace.\n *\n * No-op when there is no active span, no root span, or the root span is not an\n * `http.server` span — so framework instrumentations can call this unconditionally\n * without risking attribute pollution on non-HTTP root spans.\n */\nfunction setHttpServerSpanRouteAttribute(route: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return;\n }\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n if (spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] !== 'http.server') {\n return;\n }\n rootSpan.setAttribute(HTTP_ROUTE, route);\n}\n\nconst isLifecycleExtType = (variableToCheck: unknown): variableToCheck is ServerRequestExtType => {\n return typeof variableToCheck === 'string' && HapiLifecycleMethodNames.has(variableToCheck);\n};\n\nconst isLifecycleExtEventObj = (variableToCheck: unknown): variableToCheck is ServerExtEventsRequestObject => {\n const event = (variableToCheck as ServerExtEventsRequestObject)?.type;\n return event !== undefined && isLifecycleExtType(event);\n};\n\nconst isDirectExtInput = (variableToCheck: unknown): variableToCheck is ServerExtDirectInput => {\n return (\n Array.isArray(variableToCheck) &&\n variableToCheck.length <= 3 &&\n isLifecycleExtType(variableToCheck[0]) &&\n typeof variableToCheck[1] === 'function'\n );\n};\n\nconst isPatchableExtMethod = (\n variableToCheck: PatchableExtMethod | PatchableExtMethod[],\n): variableToCheck is PatchableExtMethod => {\n return !Array.isArray(variableToCheck);\n};\n\n/** Build the span name and attributes for a Hapi route. */\nexport const getRouteMetadata = (route: ServerRoute, pluginName?: string): SpanMetadata => {\n const attributes: SpanAttributes = {\n [HTTP_ROUTE]: route.path,\n // eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes\n [HTTP_METHOD]: route.method,\n };\n\n let name;\n if (pluginName) {\n attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.PLUGIN;\n attributes[AttributeNames.PLUGIN_NAME] = pluginName;\n name = `${pluginName}: route - ${route.path}`;\n } else {\n attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.ROUTER;\n name = `route - ${route.path}`;\n }\n\n return { attributes, name };\n};\n\n/** Build the span name and attributes for a Hapi server extension. */\nexport const getExtMetadata = (\n extPoint: ServerRequestExtType,\n pluginName?: string,\n methodName?: string,\n): SpanMetadata => {\n let baseName = `ext - ${extPoint}`;\n if (methodName && methodName !== 'method') {\n // `method` is the default name for the extension in the ServerExtEventsObject format.\n baseName = `ext - ${extPoint} - ${methodName}`;\n }\n if (pluginName) {\n return {\n attributes: {\n [AttributeNames.EXT_TYPE]: extPoint,\n [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT,\n [AttributeNames.PLUGIN_NAME]: pluginName,\n },\n name: `${pluginName}: ${baseName}`,\n };\n }\n return {\n attributes: {\n [AttributeNames.EXT_TYPE]: extPoint,\n [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT,\n },\n name: baseName,\n };\n};\n\nfunction startMetadataSpan(metadata: SpanMetadata, original: () => unknown): unknown {\n return startSpan(\n {\n name: metadata.name,\n op: `${metadata.attributes[AttributeNames.HAPI_TYPE]}.hapi`,\n attributes: {\n ...metadata.attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.orchestrion.hapi',\n },\n },\n original,\n );\n}\n\n/**\n * Patches each individual route handler method in order to create the span. It\n * does not create spans when there is no parent span.\n */\nfunction wrapRouteHandler(route: PatchableServerRoute, pluginName?: string): PatchableServerRoute {\n if (route[handlerPatched] === true) return route;\n route[handlerPatched] = true;\n\n const wrapHandler: (oldHandler: LifecycleMethod) => LifecycleMethod = oldHandler => {\n return function (this: unknown, ...params: Parameters<LifecycleMethod>) {\n if (!getActiveSpan()) {\n return oldHandler.call(this, ...params);\n }\n setHttpServerSpanRouteAttribute(route.path);\n const metadata = getRouteMetadata(route, pluginName);\n return startMetadataSpan(metadata, () => oldHandler.call(this, ...params));\n };\n };\n\n if (typeof route.handler === 'function') {\n route.handler = wrapHandler(route.handler as LifecycleMethod);\n } else if (typeof route.options === 'function') {\n const oldOptions = route.options;\n route.options = function (server: unknown): ServerRouteOptions {\n const options = oldOptions(server);\n if (typeof options.handler === 'function') {\n options.handler = wrapHandler(options.handler as LifecycleMethod);\n }\n return options;\n };\n } else if (typeof route.options?.handler === 'function') {\n route.options.handler = wrapHandler(route.options.handler as LifecycleMethod);\n }\n return route;\n}\n\n/**\n * Wraps request extension methods to add instrumentation to each new extension\n * handler. It does not create spans when there is no parent span.\n */\nfunction wrapExtMethods<T extends PatchableExtMethod | PatchableExtMethod[]>(\n method: T,\n extPoint: ServerRequestExtType,\n pluginName?: string,\n): T {\n if (Array.isArray(method)) {\n for (let i = 0; i < method.length; i++) {\n method[i] = wrapExtMethods(method[i]!, extPoint);\n }\n return method;\n } else if (isPatchableExtMethod(method)) {\n if (method[handlerPatched] === true) return method;\n method[handlerPatched] = true;\n\n const newHandler: PatchableExtMethod = function (this: unknown, ...params: Parameters<LifecycleMethod>) {\n if (!getActiveSpan()) {\n return method.apply(this, params);\n }\n const metadata = getExtMetadata(extPoint, pluginName, method.name);\n return startMetadataSpan(metadata, () => method.apply(undefined, params));\n };\n // Mark the wrapper too (not just the original)\n newHandler[handlerPatched] = true;\n return newHandler as T;\n }\n return method;\n}\n\n/**\n * Wrap the route handler(s) in the live `server.route` arguments array, mutating\n * `args[0]` in place. `args[0]` is either a single route options object or an\n * array of them. Idempotent via the `handlerPatched` marker.\n */\nexport function wrapRouteArguments(args: unknown[], pluginName?: string): void {\n const route = args[0] as PatchableServerRoute | PatchableServerRoute[];\n if (Array.isArray(route)) {\n for (let i = 0; i < route.length; i++) {\n route[i] = wrapRouteHandler(route[i]!, pluginName);\n }\n } else {\n args[0] = wrapRouteHandler(route, pluginName);\n }\n}\n\n/**\n * Wrap the extension method(s) in the live `server.ext` arguments array,\n * mutating `args` in place. Handles the three accepted input shapes:\n * `(eventsArray)`, `(lifecycleEventObject)`, and `(extTypeString, method, options)`.\n * Idempotent via the `handlerPatched` marker.\n */\nexport function wrapExtArguments(args: unknown[], pluginName?: string): void {\n if (Array.isArray(args[0])) {\n const eventsList = args[0] as ServerExtEventsObject[] | ServerExtEventsRequestObject[];\n for (let i = 0; i < eventsList.length; i++) {\n const eventObj = eventsList[i]!;\n if (isLifecycleExtType(eventObj.type)) {\n const lifecycleEventObj = eventObj as ServerExtEventsRequestObject;\n const handler = wrapExtMethods(lifecycleEventObj.method, eventObj.type, pluginName);\n lifecycleEventObj.method = handler;\n eventsList[i] = lifecycleEventObj;\n }\n }\n return;\n } else if (isDirectExtInput(args)) {\n const extInput: ServerExtDirectInput = args;\n const method: PatchableExtMethod = extInput[1];\n const handler = wrapExtMethods(method, extInput[0], pluginName);\n args[1] = handler;\n return;\n } else if (isLifecycleExtEventObj(args[0])) {\n const lifecycleEventObj = args[0];\n const handler = wrapExtMethods(lifecycleEventObj.method, lifecycleEventObj.type, pluginName);\n lifecycleEventObj.method = handler;\n }\n}\n"],"names":["getActiveSpan","getRootSpan","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","HTTP_ROUTE","HapiLifecycleMethodNames","attributes","HTTP_METHOD","AttributeNames","HapiLayerType","startSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","handlerPatched"],"mappings":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const channels = require('../../orchestrion/channels.js'); | ||
| const hapiUtils = require('./hapi-utils.js'); | ||
| const INTEGRATION_NAME = "Hapi"; | ||
| const _hapiChannelIntegration = (() => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:hapi] subscribing to channels "${channels.CHANNELS.HAPI_ROUTE}" / "${channels.CHANNELS.HAPI_EXT}"`); | ||
| diagnosticsChannel.tracingChannel(channels.CHANNELS.HAPI_ROUTE).subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| hapiUtils.wrapRouteArguments(ctx.arguments, ctx.self?.realm?.plugin); | ||
| }, | ||
| end() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| diagnosticsChannel.tracingChannel(channels.CHANNELS.HAPI_EXT).subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| hapiUtils.wrapExtArguments(ctx.arguments, ctx.self?.realm?.plugin); | ||
| }, | ||
| end() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const hapiChannelIntegration = core.defineIntegration(_hapiChannelIntegration); | ||
| exports.hapiChannelIntegration = hapiChannelIntegration; | ||
| //# sourceMappingURL=hapi.js.map |
| {"version":3,"file":"hapi.js","sources":["../../../../src/integrations/tracing-channel/hapi.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { wrapExtArguments, wrapRouteArguments } from './hapi-utils';\n\n// NOTE: same name as the OTel integration by design — when enabled, the OTel\n// 'Hapi' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Hapi' as const;\n\n/**\n * The shape orchestrion's transform attaches to the `@hapi/hapi` route/ext\n * tracing-channel `context` objects.\n *\n * `arguments` is the *live* args array passed to `server.route` / `server.ext`;\n * we mutate it in place to swap handlers for span-creating proxies. `self` is\n * the hapi server instance: the root server has `self.realm.plugin === undefined`,\n * while a plugin's clone server exposes the registering plugin's name there.\n */\ninterface HapiChannelContext {\n arguments: unknown[];\n self?: { realm?: { plugin?: string } };\n}\n\nconst _hapiChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD &&\n debug.log(`[orchestrion:hapi] subscribing to channels \"${CHANNELS.HAPI_ROUTE}\" / \"${CHANNELS.HAPI_EXT}\"`);\n\n // `subscribe` requires all five lifecycle hooks. We only act on `start`,\n // which orchestrion fires synchronously with the live args array — that's\n // the moment we mutate the handlers in place.\n diagnosticsChannel.tracingChannel(CHANNELS.HAPI_ROUTE).subscribe({\n start(rawCtx) {\n const ctx = rawCtx as HapiChannelContext;\n wrapRouteArguments(ctx.arguments, ctx.self?.realm?.plugin);\n },\n end() {},\n asyncStart() {},\n asyncEnd() {},\n error() {},\n });\n\n diagnosticsChannel.tracingChannel(CHANNELS.HAPI_EXT).subscribe({\n start(rawCtx) {\n const ctx = rawCtx as HapiChannelContext;\n wrapExtArguments(ctx.arguments, ctx.self?.realm?.plugin);\n },\n end() {},\n asyncStart() {},\n asyncEnd() {},\n error() {},\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * EXPERIMENTAL — orchestrion-driven hapi integration. Subscribes to the\n * `orchestrion:@hapi/hapi:route` / `:ext` channels injected into `@hapi/hapi`'s\n * `lib/server.js`. Requires the orchestrion runtime hook or bundler plugin.\n */\nexport const hapiChannelIntegration = defineIntegration(_hapiChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","wrapRouteArguments","wrapExtArguments","defineIntegration"],"mappings":";;;;;;;;AASA,MAAM,gBAAA,GAAmB,MAAA;AAgBzB,MAAM,2BAA2B,MAAM;AACrC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,IAAI,CAAC,mBAAmB,cAAA,EAAgB;AACtC,QAAA;AAAA,MACF;AAEA,MAAAA,sBAAA,IACEC,UAAA,CAAM,IAAI,CAAA,4CAAA,EAA+CC,iBAAA,CAAS,UAAU,CAAA,KAAA,EAAQA,iBAAA,CAAS,QAAQ,CAAA,CAAA,CAAG,CAAA;AAK1G,MAAA,kBAAA,CAAmB,cAAA,CAAeA,iBAAA,CAAS,UAAU,CAAA,CAAE,SAAA,CAAU;AAAA,QAC/D,MAAM,MAAA,EAAQ;AACZ,UAAA,MAAM,GAAA,GAAM,MAAA;AACZ,UAAAC,4BAAA,CAAmB,GAAA,CAAI,SAAA,EAAW,GAAA,CAAI,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QAC3D,CAAA;AAAA,QACA,GAAA,GAAM;AAAA,QAAC,CAAA;AAAA,QACP,UAAA,GAAa;AAAA,QAAC,CAAA;AAAA,QACd,QAAA,GAAW;AAAA,QAAC,CAAA;AAAA,QACZ,KAAA,GAAQ;AAAA,QAAC;AAAA,OACV,CAAA;AAED,MAAA,kBAAA,CAAmB,cAAA,CAAeD,iBAAA,CAAS,QAAQ,CAAA,CAAE,SAAA,CAAU;AAAA,QAC7D,MAAM,MAAA,EAAQ;AACZ,UAAA,MAAM,GAAA,GAAM,MAAA;AACZ,UAAAE,0BAAA,CAAiB,GAAA,CAAI,SAAA,EAAW,GAAA,CAAI,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QACzD,CAAA;AAAA,QACA,GAAA,GAAM;AAAA,QAAC,CAAA;AAAA,QACP,UAAA,GAAa;AAAA,QAAC,CAAA;AAAA,QACd,QAAA,GAAW;AAAA,QAAC,CAAA;AAAA,QACZ,KAAA,GAAQ;AAAA,QAAC;AAAA,OACV,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAOO,MAAM,sBAAA,GAAyBC,uBAAkB,uBAAuB;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const channels = require('../../orchestrion/channels.js'); | ||
| const redisStatementSerializer = require('../../redis/redis-statement-serializer.js'); | ||
| const tracingChannel = require('../../tracing-channel.js'); | ||
| const INTEGRATION_NAME = "IORedis"; | ||
| const ORIGIN = "auto.db.orchestrion.redis"; | ||
| const ATTR_DB_CONNECTION_STRING = "db.connection_string"; | ||
| function getConnectionOptions(self) { | ||
| return { host: self?.options?.host, port: self?.options?.port }; | ||
| } | ||
| function connectionAttributes(host, port) { | ||
| return { | ||
| [attributes.DB_SYSTEM]: "redis", | ||
| [ATTR_DB_CONNECTION_STRING]: `redis://${host}:${port}`, | ||
| [attributes.NET_PEER_NAME]: host, | ||
| [attributes.NET_PEER_PORT]: port, | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN | ||
| }; | ||
| } | ||
| const _ioredisChannelIntegration = ((options = {}) => { | ||
| const responseHook = options.responseHook; | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:ioredis] subscribing to "${channels.CHANNELS.IOREDIS_COMMAND}"/"${channels.CHANNELS.IOREDIS_CONNECT}"`); | ||
| const commandChannel = diagnosticsChannel.tracingChannel( | ||
| channels.CHANNELS.IOREDIS_COMMAND | ||
| ); | ||
| const connectChannel = diagnosticsChannel.tracingChannel( | ||
| channels.CHANNELS.IOREDIS_CONNECT | ||
| ); | ||
| core.waitForTracingChannelBinding(() => { | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| commandChannel, | ||
| (data) => { | ||
| if (!core.getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| const command = data.arguments?.[0]; | ||
| if (!command || typeof command !== "object") { | ||
| return void 0; | ||
| } | ||
| const { host, port } = getConnectionOptions(data.self); | ||
| const statement = redisStatementSerializer.defaultDbStatementSerializer(command.name, command.args ?? []); | ||
| return core.startInactiveSpan({ | ||
| name: statement, | ||
| op: "db", | ||
| attributes: { ...connectionAttributes(host, port), [attributes.DB_STATEMENT]: statement } | ||
| }); | ||
| }, | ||
| { | ||
| beforeSpanEnd(span, data) { | ||
| if ("error" in data || !responseHook) { | ||
| return; | ||
| } | ||
| const command = data.arguments?.[0]; | ||
| if (command) { | ||
| runResponseHook(responseHook, span, command, data.result); | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| tracingChannel.bindTracingChannelToSpan(connectChannel, (data) => { | ||
| if (!core.getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| const { host, port } = getConnectionOptions(data.self); | ||
| return core.startInactiveSpan({ | ||
| name: "connect", | ||
| op: "db", | ||
| attributes: { ...connectionAttributes(host, port), [attributes.DB_STATEMENT]: "connect" } | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function runResponseHook(hook, span, command, result) { | ||
| try { | ||
| hook(span, command.name, command.args, result); | ||
| } catch { | ||
| } | ||
| } | ||
| const ioredisChannelIntegration = core.defineIntegration(_ioredisChannelIntegration); | ||
| exports.ioredisChannelIntegration = ioredisChannelIntegration; | ||
| //# sourceMappingURL=ioredis.js.map |
| {"version":3,"file":"ioredis.js","sources":["../../../../src/integrations/tracing-channel/ioredis.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-deprecated -- we intentionally emit the OLD db/net semconv\n to match `@opentelemetry/instrumentation-ioredis` (and Sentry's `inferDbSpanData`, which keys off\n `db.statement`). TODO(v11): switch to the non-deprecated `db.system.name`/`db.query.text`/\n `server.address`/`server.port` conventions and drop this disable. */\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { DB_STATEMENT, DB_SYSTEM, NET_PEER_NAME, NET_PEER_PORT } from '@sentry/conventions/attributes';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getActiveSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { defaultDbStatementSerializer } from '../../redis/redis-statement-serializer';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Distinct from the OTel `Redis` integration, which is composite (node-redis +\n// ioredis + the >=5.11.0 diagnostics_channel subscriber) and stays in the set;\n// only its ioredis monkey-patch is gated off in the node SDK when this is active.\nconst INTEGRATION_NAME = 'IORedis' as const;\n\nconst ORIGIN = 'auto.db.orchestrion.redis';\n\n// todo(v11): Let's drop this as this is already covered with host and port\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\n\n/** Mirrors `@opentelemetry/instrumentation-ioredis`' response hook. Not called for failed commands. */\nexport type IORedisResponseHook = (span: Span, command: string, args: Array<string | Buffer>, result: unknown) => void;\n\nexport interface IORedisChannelIntegrationOptions {\n responseHook?: IORedisResponseHook;\n}\n\n/** Structural type for the command object ioredis passes to `sendCommand`. */\ninterface RedisCommand {\n name: string;\n args: Array<string | Buffer>;\n}\n\ninterface RedisClientLike {\n options?: { host?: string; port?: number };\n}\n\ninterface IORedisCommandContext {\n arguments?: unknown[];\n self?: RedisClientLike;\n result?: unknown;\n error?: unknown;\n}\n\ntype IORedisConnectContext = Omit<IORedisCommandContext, 'arguments'>;\n\nfunction getConnectionOptions(self: RedisClientLike | undefined): { host?: string; port?: number } {\n return { host: self?.options?.host, port: self?.options?.port };\n}\n\nfunction connectionAttributes(host: string | undefined, port: number | undefined): Record<string, unknown> {\n return {\n [DB_SYSTEM]: 'redis',\n [ATTR_DB_CONNECTION_STRING]: `redis://${host}:${port}`,\n [NET_PEER_NAME]: host,\n [NET_PEER_PORT]: port,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n };\n}\n\nconst _ioredisChannelIntegration = ((options: IORedisChannelIntegrationOptions = {}) => {\n const responseHook = options.responseHook;\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD &&\n debug.log(`[orchestrion:ioredis] subscribing to \"${CHANNELS.IOREDIS_COMMAND}\"/\"${CHANNELS.IOREDIS_CONNECT}\"`);\n\n const commandChannel = diagnosticsChannel.tracingChannel<IORedisCommandContext, IORedisCommandContext>(\n CHANNELS.IOREDIS_COMMAND,\n );\n const connectChannel = diagnosticsChannel.tracingChannel<IORedisConnectContext, IORedisConnectContext>(\n CHANNELS.IOREDIS_CONNECT,\n );\n\n // `bindTracingChannelToSpan` uses `bindStore`, which needs the async-context\n // binding that `initOpenTelemetry()` registers after integration `setupOnce` —\n // defer until it's available (matches the native redis diagnostics-channel subscriber).\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n commandChannel,\n data => {\n // ioredis' `requireParentSpan` default: only create a span under an active span.\n if (!getActiveSpan()) {\n return undefined;\n }\n const command = data.arguments?.[0] as RedisCommand | undefined;\n if (!command || typeof command !== 'object') {\n return undefined;\n }\n const { host, port } = getConnectionOptions(data.self);\n const statement = defaultDbStatementSerializer(command.name, command.args ?? []);\n return startInactiveSpan({\n name: statement,\n op: 'db',\n attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: statement },\n });\n },\n {\n beforeSpanEnd(span, data) {\n if ('error' in data || !responseHook) {\n return;\n }\n const command = data.arguments?.[0] as RedisCommand | undefined;\n if (command) {\n runResponseHook(responseHook, span, command, data.result);\n }\n },\n },\n );\n\n bindTracingChannelToSpan(connectChannel, data => {\n if (!getActiveSpan()) {\n return undefined;\n }\n const { host, port } = getConnectionOptions(data.self);\n return startInactiveSpan({\n name: 'connect',\n op: 'db',\n attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: 'connect' },\n });\n });\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction runResponseHook(hook: IORedisResponseHook, span: Span, command: RedisCommand, result: unknown): void {\n try {\n hook(span, command.name, command.args, result);\n } catch {\n // never let a user-provided response hook break instrumentation\n }\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven ioredis integration. Subscribes to\n * `orchestrion:ioredis:command` / `:connect` (injected into ioredis' `<5.11.0`\n * `sendCommand`/`connect`) and creates db spans matching\n * `@opentelemetry/instrumentation-ioredis`. Requires the orchestrion runtime hook\n * or bundler plugin.\n */\nexport const ioredisChannelIntegration = defineIntegration(_ioredisChannelIntegration);\n"],"names":["DB_SYSTEM","NET_PEER_NAME","NET_PEER_PORT","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","DEBUG_BUILD","debug","CHANNELS","waitForTracingChannelBinding","bindTracingChannelToSpan","getActiveSpan","defaultDbStatementSerializer","startInactiveSpan","DB_STATEMENT","defineIntegration"],"mappings":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const channels = require('../../orchestrion/channels.js'); | ||
| const tracingChannel = require('../../tracing-channel.js'); | ||
| const INTEGRATION_NAME = "OpenAI"; | ||
| const ORIGIN = "auto.ai.orchestrion.openai"; | ||
| const INSTRUMENTED_CHANNELS = [ | ||
| { channel: channels.CHANNELS.OPENAI_CHAT, operation: "chat" }, | ||
| { channel: channels.CHANNELS.OPENAI_RESPONSES, operation: "chat" }, | ||
| { channel: channels.CHANNELS.OPENAI_EMBEDDINGS, operation: "embeddings" }, | ||
| { channel: channels.CHANNELS.OPENAI_CONVERSATIONS, operation: "chat" } | ||
| ]; | ||
| let subscribed = false; | ||
| const _openaiChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel || subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| core.waitForTracingChannelBinding(() => { | ||
| for (const { channel, operation } of INSTRUMENTED_CHANNELS) { | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:openai] subscribing to channel "${channel}"`); | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channel), | ||
| (data) => createGenAiSpan(data, operation, options), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| core.addOpenAiResponseAttributes(span, data.result, core.resolveAIRecordingOptions(options).recordOutputs); | ||
| }, | ||
| // Streaming: the result is a `Stream` consumed later, so instrument it and let it end the span. | ||
| deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, options) | ||
| } | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function createGenAiSpan(data, operation, options) { | ||
| if (core._INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) { | ||
| return void 0; | ||
| } | ||
| const args = data.arguments ?? []; | ||
| const params = args[0]; | ||
| const { recordInputs } = core.resolveAIRecordingOptions(options); | ||
| const enableTruncation = core.shouldEnableTruncation(options.enableTruncation); | ||
| const attributes = core.extractOpenAiRequestAttributes(args, operation); | ||
| attributes[core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN; | ||
| const model = params?.model || "unknown"; | ||
| const span = core.startInactiveSpan({ | ||
| name: `${operation} ${model}`, | ||
| op: `gen_ai.${operation}`, | ||
| attributes | ||
| }); | ||
| if (recordInputs && params) { | ||
| core.addOpenAiRequestAttributes(span, params, operation, enableTruncation); | ||
| } | ||
| return span; | ||
| } | ||
| function isAsyncIterable(value) { | ||
| return !!value && typeof value[Symbol.asyncIterator] === "function"; | ||
| } | ||
| function wrapStreamResult(span, data, options) { | ||
| const result = data.result; | ||
| if (!isAsyncIterable(result)) { | ||
| return false; | ||
| } | ||
| const { recordOutputs } = core.resolveAIRecordingOptions(options); | ||
| const iterate = result[Symbol.asyncIterator].bind(result); | ||
| const instrumented = core.instrumentOpenAiStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs ?? false); | ||
| result[Symbol.asyncIterator] = () => instrumented; | ||
| return true; | ||
| } | ||
| const openaiChannelIntegration = core.defineIntegration(_openaiChannelIntegration); | ||
| exports.openaiChannelIntegration = openaiChannelIntegration; | ||
| //# sourceMappingURL=openai.js.map |
| {"version":3,"file":"openai.js","sources":["../../../../src/integrations/tracing-channel/openai.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, OpenAiOptions, Span, SpanAttributeValue } from '@sentry/core';\nimport {\n _INTERNAL_shouldSkipAiProviderWrapping,\n addOpenAiRequestAttributes,\n addOpenAiResponseAttributes,\n debug,\n defineIntegration,\n extractOpenAiRequestAttributes,\n instrumentOpenAiStream,\n resolveAIRecordingOptions,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Same name as the OTel integration by design: when enabled, the OTel 'OpenAI'\n// integration is dropped from the default set (see the Node opt-in loader).\nconst INTEGRATION_NAME = 'OpenAI' as const;\n\n// Distinct from the proxy's `auto.ai.openai` so spans from the orchestrion path\n// are attributable separately from the OTel/proxy one.\nconst ORIGIN = 'auto.ai.orchestrion.openai';\n\n// Each instrumented `create` method maps to the gen_ai operation its span reports.\nconst INSTRUMENTED_CHANNELS = [\n { channel: CHANNELS.OPENAI_CHAT, operation: 'chat' },\n { channel: CHANNELS.OPENAI_RESPONSES, operation: 'chat' },\n { channel: CHANNELS.OPENAI_EMBEDDINGS, operation: 'embeddings' },\n { channel: CHANNELS.OPENAI_CONVERSATIONS, operation: 'chat' },\n] as const;\n\n/**\n * The context object orchestrion shares across the tracing-channel lifecycle hooks: `arguments` is the\n * live args array passed to `Completions.create(body, options)`, and Node's `tracingChannel` attaches\n * `result` when the returned promise settles.\n */\ninterface OpenAiChatChannelContext {\n arguments: unknown[];\n result?: unknown;\n}\n\nlet subscribed = false;\n\nconst _openaiChannelIntegration = ((options: OpenAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19, and a second `init()` would double-subscribe.\n if (!diagnosticsChannel.tracingChannel || subscribed) {\n return;\n }\n subscribed = true;\n\n // `bindTracingChannelToSpan` needs the async-context binding that `initOpenTelemetry()` registers\n // after `setupOnce` runs, so wait for it before subscribing.\n waitForTracingChannelBinding(() => {\n for (const { channel, operation } of INSTRUMENTED_CHANNELS) {\n DEBUG_BUILD && debug.log(`[orchestrion:openai] subscribing to channel \"${channel}\"`);\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<OpenAiChatChannelContext>(channel),\n data => createGenAiSpan(data, operation, options),\n {\n beforeSpanEnd: (span, data) => {\n addOpenAiResponseAttributes(span, data.result, resolveAIRecordingOptions(options).recordOutputs);\n },\n // Streaming: the result is a `Stream` consumed later, so instrument it and let it end the span.\n deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, options),\n },\n );\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Build the span for an instrumented `create` call.\n * Returning `undefined` opts the payload out so no span is opened.\n */\nfunction createGenAiSpan(data: OpenAiChatChannelContext, operation: string, options: OpenAiOptions): Span | undefined {\n // langchain drives the openai SDK itself and instruments at its own layer; skip here to avoid double spans.\n if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) {\n return undefined;\n }\n\n const args = data.arguments ?? [];\n const params = args[0] as Record<string, unknown> | undefined;\n\n const { recordInputs } = resolveAIRecordingOptions(options);\n const enableTruncation = shouldEnableTruncation(options.enableTruncation);\n\n const attributes = extractOpenAiRequestAttributes(args, operation);\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN;\n const model = (params?.model as string) || 'unknown';\n\n const span = startInactiveSpan({\n name: `${operation} ${model}`,\n op: `gen_ai.${operation}`,\n attributes: attributes as Record<string, SpanAttributeValue>,\n });\n\n if (recordInputs && params) {\n addOpenAiRequestAttributes(span, params, operation, enableTruncation);\n }\n\n return span;\n}\n\ntype AsyncIterableStream = { [Symbol.asyncIterator]: () => AsyncIterator<unknown> };\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterableStream {\n return !!value && typeof (value as AsyncIterableStream)[Symbol.asyncIterator] === 'function';\n}\n\n/**\n * For a streaming `create({ stream: true })` the result is a `Stream` the caller consumes later. We can't\n * swap what `create` returns, but the `Stream` in `data.result` is the same instance the caller holds and\n * `asyncEnd` fires before the caller iterates — so we patch its async iterator in place to run through\n * `instrumentOpenAiStream`, which accumulates the streamed attributes and ends the span when iteration finishes.\n * Only a streaming call resolves to an async-iterable, so that check alone distinguishes it. Returns `true`\n * to hand span-ending ownership to `instrumentOpenAiStream`; `false` for non-streaming/errored results, which end\n * via the normal `beforeSpanEnd` path.\n */\nfunction wrapStreamResult(span: Span, data: OpenAiChatChannelContext, options: OpenAiOptions): boolean {\n const result = data.result;\n if (!isAsyncIterable(result)) {\n return false;\n }\n\n const { recordOutputs } = resolveAIRecordingOptions(options);\n const iterate = result[Symbol.asyncIterator].bind(result);\n const instrumented = instrumentOpenAiStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs ?? false);\n result[Symbol.asyncIterator] = () => instrumented;\n\n return true;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven OpenAI integration. Subscribes to the `orchestrion:openai:*`\n * diagnostics_channels injected into `openai`'s `create` methods (chat completions, responses, embeddings,\n * conversations), so it requires the orchestrion runtime hook or bundler plugin.\n */\nexport const openaiChannelIntegration = defineIntegration(_openaiChannelIntegration);\n"],"names":["CHANNELS","waitForTracingChannelBinding","DEBUG_BUILD","debug","bindTracingChannelToSpan","addOpenAiResponseAttributes","resolveAIRecordingOptions","_INTERNAL_shouldSkipAiProviderWrapping","shouldEnableTruncation","extractOpenAiRequestAttributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","startInactiveSpan","addOpenAiRequestAttributes","instrumentOpenAiStream","defineIntegration"],"mappings":";;;;;;;;AAsBA,MAAM,gBAAA,GAAmB,QAAA;AAIzB,MAAM,MAAA,GAAS,4BAAA;AAGf,MAAM,qBAAA,GAAwB;AAAA,EAC5B,EAAE,OAAA,EAASA,iBAAA,CAAS,WAAA,EAAa,WAAW,MAAA,EAAO;AAAA,EACnD,EAAE,OAAA,EAASA,iBAAA,CAAS,gBAAA,EAAkB,WAAW,MAAA,EAAO;AAAA,EACxD,EAAE,OAAA,EAASA,iBAAA,CAAS,iBAAA,EAAmB,WAAW,YAAA,EAAa;AAAA,EAC/D,EAAE,OAAA,EAASA,iBAAA,CAAS,oBAAA,EAAsB,WAAW,MAAA;AACvD,CAAA;AAYA,IAAI,UAAA,GAAa,KAAA;AAEjB,MAAM,yBAAA,IAA6B,CAAC,OAAA,GAAyB,EAAC,KAAM;AAClE,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,kBAAA,CAAmB,cAAA,IAAkB,UAAA,EAAY;AACpD,QAAA;AAAA,MACF;AACA,MAAA,UAAA,GAAa,IAAA;AAIb,MAAAC,iCAAA,CAA6B,MAAM;AACjC,QAAA,KAAA,MAAW,EAAE,OAAA,EAAS,SAAA,EAAU,IAAK,qBAAA,EAAuB;AAC1D,UAAAC,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,CAAA,6CAAA,EAAgD,OAAO,CAAA,CAAA,CAAG,CAAA;AACnF,UAAAC,uCAAA;AAAA,YACE,kBAAA,CAAmB,eAAyC,OAAO,CAAA;AAAA,YACnE,CAAA,IAAA,KAAQ,eAAA,CAAgB,IAAA,EAAM,SAAA,EAAW,OAAO,CAAA;AAAA,YAChD;AAAA,cACE,aAAA,EAAe,CAAC,IAAA,EAAM,IAAA,KAAS;AAC7B,gBAAAC,gCAAA,CAA4B,MAAM,IAAA,CAAK,MAAA,EAAQC,8BAAA,CAA0B,OAAO,EAAE,aAAa,CAAA;AAAA,cACjG,CAAA;AAAA;AAAA,cAEA,YAAA,EAAc,CAAC,EAAE,IAAA,EAAM,MAAK,KAAM,gBAAA,CAAiB,IAAA,EAAM,IAAA,EAAM,OAAO;AAAA;AACxE,WACF;AAAA,QACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAMA,SAAS,eAAA,CAAgB,IAAA,EAAgC,SAAA,EAAmB,OAAA,EAA0C;AAEpH,EAAA,IAAIC,2CAAA,CAAuC,gBAAgB,CAAA,EAAG;AAC5D,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,IAAa,EAAC;AAChC,EAAA,MAAM,MAAA,GAAS,KAAK,CAAC,CAAA;AAErB,EAAA,MAAM,EAAE,YAAA,EAAa,GAAID,8BAAA,CAA0B,OAAO,CAAA;AAC1D,EAAA,MAAM,gBAAA,GAAmBE,2BAAA,CAAuB,OAAA,CAAQ,gBAAgB,CAAA;AAExE,EAAA,MAAM,UAAA,GAAaC,mCAAA,CAA+B,IAAA,EAAM,SAAS,CAAA;AACjE,EAAA,UAAA,CAAWC,qCAAgC,CAAA,GAAI,MAAA;AAC/C,EAAA,MAAM,KAAA,GAAS,QAAQ,KAAA,IAAoB,SAAA;AAE3C,EAAA,MAAM,OAAOC,sBAAA,CAAkB;AAAA,IAC7B,IAAA,EAAM,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,KAAK,CAAA,CAAA;AAAA,IAC3B,EAAA,EAAI,UAAU,SAAS,CAAA,CAAA;AAAA,IACvB;AAAA,GACD,CAAA;AAED,EAAA,IAAI,gBAAgB,MAAA,EAAQ;AAC1B,IAAAC,+BAAA,CAA2B,IAAA,EAAM,MAAA,EAAQ,SAAA,EAAW,gBAAgB,CAAA;AAAA,EACtE;AAEA,EAAA,OAAO,IAAA;AACT;AAIA,SAAS,gBAAgB,KAAA,EAA8C;AACrE,EAAA,OAAO,CAAC,CAAC,KAAA,IAAS,OAAQ,KAAA,CAA8B,MAAA,CAAO,aAAa,CAAA,KAAM,UAAA;AACpF;AAWA,SAAS,gBAAA,CAAiB,IAAA,EAAY,IAAA,EAAgC,OAAA,EAAiC;AACrG,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,EAAA,IAAI,CAAC,eAAA,CAAgB,MAAM,CAAA,EAAG;AAC5B,IAAA,OAAO,KAAA;AAAA,EACT;AAEA,EAAA,MAAM,EAAE,aAAA,EAAc,GAAIN,8BAAA,CAA0B,OAAO,CAAA;AAC3D,EAAA,MAAM,UAAU,MAAA,CAAO,MAAA,CAAO,aAAa,CAAA,CAAE,KAAK,MAAM,CAAA;AACxD,EAAA,MAAM,YAAA,GAAeO,2BAAA,CAAuB,EAAE,CAAC,MAAA,CAAO,aAAa,GAAG,OAAA,EAAQ,EAAG,IAAA,EAAM,aAAA,IAAiB,KAAK,CAAA;AAC7G,EAAA,MAAA,CAAO,MAAA,CAAO,aAAa,CAAA,GAAI,MAAM,YAAA;AAErC,EAAA,OAAO,IAAA;AACT;AAOO,MAAM,wBAAA,GAA2BC,uBAAkB,yBAAyB;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const channels = require('../../orchestrion/channels.js'); | ||
| const tracingChannel = require('../../tracing-channel.js'); | ||
| const INTEGRATION_NAME = "Postgres"; | ||
| const ORIGIN = "auto.db.orchestrion.postgres"; | ||
| const ATTR_DB_SYSTEM = "db.system"; | ||
| const ATTR_DB_NAME = "db.name"; | ||
| const ATTR_DB_CONNECTION_STRING = "db.connection_string"; | ||
| const ATTR_DB_USER = "db.user"; | ||
| const ATTR_DB_STATEMENT = "db.statement"; | ||
| const ATTR_NET_PEER_NAME = "net.peer.name"; | ||
| const ATTR_NET_PEER_PORT = "net.peer.port"; | ||
| const ATTR_PG_PLAN = "db.postgresql.plan"; | ||
| const ATTR_PG_IDLE_TIMEOUT = "db.postgresql.idle.timeout.millis"; | ||
| const ATTR_PG_MAX_CLIENT = "db.postgresql.max.client"; | ||
| const DB_SYSTEM_POSTGRESQL = "postgresql"; | ||
| const SPAN_QUERY_FALLBACK = "pg.query"; | ||
| const SPAN_CONNECT = "pg.connect"; | ||
| const SPAN_POOL_CONNECT = "pg-pool.connect"; | ||
| const _postgresChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| core.waitForTracingChannelBinding(() => { | ||
| subscribeQueryLikeChannel(channels.CHANNELS.PG_QUERY, querySpanOptions, { deferStreamedResult: true }); | ||
| if (!options.ignoreConnectSpans) { | ||
| subscribeQueryLikeChannel(channels.CHANNELS.PG_CONNECT, connectSpanOptions); | ||
| subscribeQueryLikeChannel(channels.CHANNELS.PGPOOL_CONNECT, poolConnectSpanOptions); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function subscribeQueryLikeChannel(channelName, getSpanOptions, { deferStreamedResult = false } = {}) { | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:pg] subscribing to channel "${channelName}"`); | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channelName), | ||
| (data) => { | ||
| if (!core.getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| data._sentryCallerScope = core.getCurrentScope(); | ||
| return core.startInactiveSpan({ ...getSpanOptions(data), kind: core.SPAN_KIND.CLIENT }); | ||
| }, | ||
| // `connect`/`pool-connect` resolve with a persistent `Client` (itself an | ||
| // `EventEmitter`), which is NOT a streamed result. Deferring their span | ||
| // to that emitter's `'end'`/`'error'` would keep it open for the whole | ||
| // connection lifetime, so it never ends in time and is dropped. Only | ||
| // `query` can return a streamable `Submittable`, so only it defers. | ||
| deferStreamedResult ? { | ||
| // Streamable `Submittable` (e.g. `client.query(new Query())`) | ||
| // returns an emitter that orchestrion stores on `ctx.result` while | ||
| // firing no async events; the query isn't done until the emitter | ||
| // emits `'end'`/`'error'`. Defer ending to those events for that | ||
| // path; the callback, promise, and sync-throw paths carry no | ||
| // emitter, so the helper ends the span as usual. | ||
| deferSpanEnd({ data, end }) { | ||
| const result = data.result; | ||
| if (!result || typeof result !== "object" || !hasOnMethod(result)) { | ||
| return false; | ||
| } | ||
| const callerScope = data._sentryCallerScope; | ||
| if (callerScope) { | ||
| core.bindScopeToEmitter(result, callerScope); | ||
| } | ||
| result.on("error", (err) => end(err)); | ||
| result.on("end", () => end()); | ||
| return true; | ||
| } | ||
| } : void 0 | ||
| ); | ||
| } | ||
| function querySpanOptions(ctx) { | ||
| const params = ctx.self?.connectionParameters ?? {}; | ||
| const queryConfig = extractQueryConfig(ctx.arguments); | ||
| return { | ||
| // The description is the SQL statement | ||
| name: queryConfig?.text ?? SPAN_QUERY_FALLBACK, | ||
| op: "db", | ||
| attributes: { | ||
| ...getConnectionAttributes(params), | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [ATTR_DB_STATEMENT]: queryConfig?.text || void 0, | ||
| [ATTR_PG_PLAN]: typeof queryConfig?.name === "string" ? queryConfig.name : void 0 | ||
| } | ||
| }; | ||
| } | ||
| function connectSpanOptions(ctx) { | ||
| const params = ctx.self?.connectionParameters ?? {}; | ||
| return { name: SPAN_CONNECT, op: "db", attributes: getConnectionAttributes(params) }; | ||
| } | ||
| function poolConnectSpanOptions(ctx) { | ||
| const opts = ctx.self?.options ?? {}; | ||
| return { name: SPAN_POOL_CONNECT, op: "db", attributes: getPoolConnectionAttributes(opts) }; | ||
| } | ||
| function hasOnMethod(obj) { | ||
| return "on" in obj && typeof obj.on === "function"; | ||
| } | ||
| function extractQueryConfig(args) { | ||
| const arg0 = args[0]; | ||
| if (typeof arg0 === "string") { | ||
| return { text: arg0 }; | ||
| } | ||
| if (arg0 && typeof arg0 === "object" && typeof arg0.text === "string") { | ||
| const obj = arg0; | ||
| return { text: obj.text, name: obj.name }; | ||
| } | ||
| return void 0; | ||
| } | ||
| function getConnectionAttributes(params) { | ||
| return { | ||
| [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL, | ||
| [ATTR_DB_CONNECTION_STRING]: getConnectionString(params), | ||
| [ATTR_DB_NAME]: params.database, | ||
| [ATTR_DB_USER]: params.user, | ||
| [ATTR_NET_PEER_NAME]: params.host, | ||
| [ATTR_NET_PEER_PORT]: Number.isInteger(params.port) ? params.port : void 0 | ||
| }; | ||
| } | ||
| function getPoolConnectionAttributes(opts) { | ||
| let url; | ||
| try { | ||
| url = opts.connectionString ? new URL(opts.connectionString) : void 0; | ||
| } catch { | ||
| url = void 0; | ||
| } | ||
| const database = url?.pathname.slice(1) || opts.database; | ||
| const host = url?.hostname || opts.host; | ||
| const port = Number(url?.port) || (Number.isInteger(opts.port) ? opts.port : void 0); | ||
| const user = url?.username || opts.user; | ||
| return { | ||
| [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL, | ||
| [ATTR_DB_CONNECTION_STRING]: getConnectionString(opts), | ||
| [ATTR_PG_IDLE_TIMEOUT]: opts.idleTimeoutMillis, | ||
| [ATTR_PG_MAX_CLIENT]: opts.max, | ||
| [ATTR_DB_NAME]: database, | ||
| [ATTR_NET_PEER_PORT]: port, | ||
| // these two come from a url parse and slice, can be '' | ||
| [ATTR_NET_PEER_NAME]: host || void 0, | ||
| [ATTR_DB_USER]: user || void 0 | ||
| }; | ||
| } | ||
| function getConnectionString(params) { | ||
| if (params.connectionString) { | ||
| try { | ||
| const url = new URL(params.connectionString); | ||
| url.username = ""; | ||
| url.password = ""; | ||
| return url.toString(); | ||
| } catch { | ||
| return "postgresql://localhost:5432/"; | ||
| } | ||
| } | ||
| const host = params.host || "localhost"; | ||
| const port = params.port || 5432; | ||
| const database = params.database || ""; | ||
| return `postgresql://${host}:${port}/${database}`; | ||
| } | ||
| const postgresChannelIntegration = core.defineIntegration(_postgresChannelIntegration); | ||
| exports.postgresChannelIntegration = postgresChannelIntegration; | ||
| //# sourceMappingURL=postgres.js.map |
| {"version":3,"file":"postgres.js","sources":["../../../../src/integrations/tracing-channel/postgres.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, SpanAttributes } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getActiveSpan,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_KIND,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, the OTel 'Postgres' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Postgres' as const;\n\n// Only the query span carries an origin (the connect/pool-connect spans don't,\n// so they default to 'manual').\nconst ORIGIN = 'auto.db.orchestrion.postgres';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions, inlined to keep this\n// integration free of `@opentelemetry/*` deps.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\nconst ATTR_PG_PLAN = 'db.postgresql.plan';\nconst ATTR_PG_IDLE_TIMEOUT = 'db.postgresql.idle.timeout.millis';\nconst ATTR_PG_MAX_CLIENT = 'db.postgresql.max.client';\nconst DB_SYSTEM_POSTGRESQL = 'postgresql';\n\n// We set `op: 'db'` and the SQL description directly here (same as mysql\n// orchestrion) rather than relying on the OTel pipeline's `inferDbSpanData`\n// processor, which only runs in the node SDK, so setting them here is what\n// makes the spans correct on the other runtimes\n//\n// The user-visible span is identical to OTel: query spans are named after\n// `db.statement`; connect/pool-connect spans keep these names.\nconst SPAN_QUERY_FALLBACK = 'pg.query';\nconst SPAN_CONNECT = 'pg.connect';\nconst SPAN_POOL_CONNECT = 'pg-pool.connect';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context`. Documented here rather\n * than imported because orchestrion's runtime doesn't export it.\n */\ninterface PgChannelContext {\n // The live args array passed to the wrapped `query`/`connect` call.\n arguments: unknown[];\n self?: unknown;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto a streamed `Submittable` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface PgConnectionParams {\n database?: string;\n host?: string;\n port?: number;\n user?: string;\n connectionString?: string;\n}\n\ninterface PgPoolOptions extends PgConnectionParams {\n idleTimeoutMillis?: number;\n // pg-pool stores the max pool size as `max` (defaulting it to 10 in its\n // constructor). The OTel pg instrumentation reads a `maxClient` field that\n // pg-pool never sets, so its `db.postgresql.max.client` attribute is always\n // dropped; we read the real `max` so the attribute is actually populated.\n max?: number;\n}\n\nconst _postgresChannelIntegration = ((options: { ignoreConnectSpans?: boolean } = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n waitForTracingChannelBinding(() => {\n // Query spans: `pg`/native `Client.prototype.query`. Only this channel can return a streamable\n // `Submittable` result, so it's the only one that defers span-ending to the emitter (see below).\n subscribeQueryLikeChannel(CHANNELS.PG_QUERY, querySpanOptions, { deferStreamedResult: true });\n\n // Connect spans, gated by `ignoreConnectSpans` (same as OTel pg).\n // `Client.prototype.connect` (pg + native)\n // and `Pool.prototype.connect` (pg-pool).\n if (!options.ignoreConnectSpans) {\n subscribeQueryLikeChannel(CHANNELS.PG_CONNECT, connectSpanOptions);\n subscribeQueryLikeChannel(CHANNELS.PGPOOL_CONNECT, poolConnectSpanOptions);\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Subscribe to a pg tracing-channel and manage a span across its lifecycle.\n * Shared by the query/connect/pool-connect channels. They differ only in how\n * the span's name + attributes are built (`getSpanOptions`), and whether the\n * result can be a streamable emitter (`deferStreamedResult`, query-only).\n */\nfunction subscribeQueryLikeChannel(\n channelName: string,\n getSpanOptions: (ctx: PgChannelContext) => { name: string; op: string; attributes: SpanAttributes },\n { deferStreamedResult = false }: { deferStreamedResult?: boolean } = {},\n): void {\n DEBUG_BUILD && debug.log(`[orchestrion:pg] subscribing to channel \"${channelName}\"`);\n\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<PgChannelContext>(channelName),\n data => {\n // Only instrument when there's an active span; returning `undefined` opts this call out entirely,\n // leaving the active context untouched (e.g. connects issued during app startup).\n if (!getActiveSpan()) {\n return undefined;\n }\n\n // Capture the caller's scope while still synchronously inside the call, for the streamed path:\n // pg dispatches a `Submittable` emitter's events outside the original async scope, so `deferSpanEnd`\n // replays this scope onto that emitter.\n data._sentryCallerScope = getCurrentScope();\n\n // `kind: CLIENT` mirrors the OTel pg instrumentation, so the emitted\n // `otel.kind` matches across the OTel and diagnostics-channel paths.\n return startInactiveSpan({ ...getSpanOptions(data), kind: SPAN_KIND.CLIENT });\n },\n // `connect`/`pool-connect` resolve with a persistent `Client` (itself an\n // `EventEmitter`), which is NOT a streamed result. Deferring their span\n // to that emitter's `'end'`/`'error'` would keep it open for the whole\n // connection lifetime, so it never ends in time and is dropped. Only\n // `query` can return a streamable `Submittable`, so only it defers.\n deferStreamedResult\n ? {\n // Streamable `Submittable` (e.g. `client.query(new Query())`)\n // returns an emitter that orchestrion stores on `ctx.result` while\n // firing no async events; the query isn't done until the emitter\n // emits `'end'`/`'error'`. Defer ending to those events for that\n // path; the callback, promise, and sync-throw paths carry no\n // emitter, so the helper ends the span as usual.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope onto the emitter so listeners theu\n // user attaches after the call returns (and any spans they start)\n // nest under the caller, not a fresh root trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n }\n : undefined,\n );\n}\n\nfunction querySpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};\n const queryConfig = extractQueryConfig(ctx.arguments);\n return {\n // The description is the SQL statement\n name: queryConfig?.text ?? SPAN_QUERY_FALLBACK,\n op: 'db',\n attributes: {\n ...getConnectionAttributes(params),\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [ATTR_DB_STATEMENT]: queryConfig?.text || undefined,\n [ATTR_PG_PLAN]: typeof queryConfig?.name === 'string' ? queryConfig.name : undefined,\n },\n };\n}\n\nfunction connectSpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};\n // No origin set -> defaults to 'manual'\n return { name: SPAN_CONNECT, op: 'db', attributes: getConnectionAttributes(params) };\n}\n\nfunction poolConnectSpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const opts = (ctx.self as { options?: PgPoolOptions } | undefined)?.options ?? {};\n return { name: SPAN_POOL_CONNECT, op: 'db', attributes: getPoolConnectionAttributes(opts) };\n}\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\n// `client.query(text, cb?)`, `client.query(text, values, cb?)`, and\n// `client.query(configObj, cb?)` are all valid; normalize to `{ text, name }`\n// (the only fields the span needs). Returns undefined for invalid args.\nfunction extractQueryConfig(args: unknown[]): { text: string; name?: unknown } | undefined {\n const arg0 = args[0];\n if (typeof arg0 === 'string') {\n return { text: arg0 };\n }\n if (arg0 && typeof arg0 === 'object' && typeof (arg0 as { text?: unknown }).text === 'string') {\n const obj = arg0 as { text: string; name?: unknown };\n return { text: obj.text, name: obj.name };\n }\n return undefined;\n}\n\nfunction getConnectionAttributes(params: PgConnectionParams): SpanAttributes {\n return {\n [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL,\n [ATTR_DB_CONNECTION_STRING]: getConnectionString(params),\n [ATTR_DB_NAME]: params.database,\n [ATTR_DB_USER]: params.user,\n [ATTR_NET_PEER_NAME]: params.host,\n [ATTR_NET_PEER_PORT]: Number.isInteger(params.port) ? params.port : undefined,\n };\n}\n\nfunction getPoolConnectionAttributes(opts: PgPoolOptions): SpanAttributes {\n let url: URL | undefined;\n try {\n url = opts.connectionString ? new URL(opts.connectionString) : undefined;\n } catch {\n url = undefined;\n }\n const database = url?.pathname.slice(1) || opts.database;\n const host = url?.hostname || opts.host;\n // Mirror OTel's `getSemanticAttributesFromPoolConnection`: prefer the URL's\n // port, but fall back to an explicit `opts.port` when the connection string\n // omits it (`Number('')` / `Number(undefined)` -> falsy).\n const port = Number(url?.port) || (Number.isInteger(opts.port) ? opts.port : undefined);\n const user = url?.username || opts.user;\n return {\n [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL,\n [ATTR_DB_CONNECTION_STRING]: getConnectionString(opts),\n [ATTR_PG_IDLE_TIMEOUT]: opts.idleTimeoutMillis,\n [ATTR_PG_MAX_CLIENT]: opts.max,\n [ATTR_DB_NAME]: database,\n [ATTR_NET_PEER_PORT]: port,\n // these two come from a url parse and slice, can be ''\n [ATTR_NET_PEER_NAME]: host || undefined,\n [ATTR_DB_USER]: user || undefined,\n };\n}\n\n// Builds `postgresql://host:port/database`, masking credentials when a raw\n// connection string was provided.\nfunction getConnectionString(params: PgConnectionParams): string {\n if (params.connectionString) {\n try {\n const url = new URL(params.connectionString);\n url.username = '';\n url.password = '';\n return url.toString();\n } catch {\n return 'postgresql://localhost:5432/';\n }\n }\n const host = params.host || 'localhost';\n const port = params.port || 5432;\n const database = params.database || '';\n return `postgresql://${host}:${port}/${database}`;\n}\n\n/**\n * EXPERIMENTAL: orchestrion-driven `pg` (node-postgres) integration.\n *\n * Subscribes to the `orchestrion:pg:query`/`:connect` and\n * `orchestrion:pg-pool:connect` diagnostics_channels that the orchestrion code\n * transform injects into `pg`'s `Client.prototype.query`/`connect`\n * and `pg-pool`'s `Pool.prototype.connect`. Requires the orchestrion runtime\n * hook or bundler plugin to be active.\n */\nexport const postgresChannelIntegration = defineIntegration(_postgresChannelIntegration);\n"],"names":["waitForTracingChannelBinding","CHANNELS","DEBUG_BUILD","debug","bindTracingChannelToSpan","getActiveSpan","getCurrentScope","startInactiveSpan","SPAN_KIND","bindScopeToEmitter","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","defineIntegration"],"mappings":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const core = require('@sentry/core'); | ||
| const index = require('../../vercel-ai/index.js'); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const vercelAiOrchestrionV6Subscriber = require('../../vercel-ai/vercel-ai-orchestrion-v6-subscriber.js'); | ||
| const _vercelAiChannelIntegration = ((options = {}) => { | ||
| const parentIntegration = index.vercelAiIntegration(options); | ||
| return core.extendIntegration(parentIntegration, { | ||
| options, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| core.waitForTracingChannelBinding(() => { | ||
| vercelAiOrchestrionV6Subscriber.subscribeVercelAiOrchestrionChannels(diagnosticsChannel.tracingChannel, options); | ||
| }); | ||
| } | ||
| }); | ||
| }); | ||
| const vercelAiChannelIntegration = core.defineIntegration(_vercelAiChannelIntegration); | ||
| exports.vercelAiChannelIntegration = vercelAiChannelIntegration; | ||
| //# sourceMappingURL=vercel-ai.js.map |
| {"version":3,"file":"vercel-ai.js","sources":["../../../../src/integrations/tracing-channel/vercel-ai.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration, extendIntegration, waitForTracingChannelBinding } from '@sentry/core';\nimport { vercelAiIntegration as baseVercelAiIntegration } from '../../vercel-ai';\nimport * as dc from 'node:diagnostics_channel';\nimport { subscribeVercelAiOrchestrionChannels } from '../../vercel-ai/vercel-ai-orchestrion-v6-subscriber';\n\ntype VercelAiOptions = Parameters<typeof baseVercelAiIntegration>[0];\n\n// In channel-based (orchestrion) mode we emit our own `gen_ai.*` spans from the\n// diagnostics channels. The `ai` SDK would otherwise emit its own native\n// OpenTelemetry spans whenever the user enables `experimental_telemetry`, which\n// would be duplicates. Rather than dropping those after the fact, the v6\n// subscriber suppresses them at the source: it flips the wrapped call's\n// `experimental_telemetry.isEnabled` to `false`, so `ai` falls back to its\n// internal no-op tracer and never creates the native spans in the first place.\n// See `subscribeVercelAiOrchestrionChannels`.\nconst _vercelAiChannelIntegration = ((options: VercelAiOptions = {}) => {\n const parentIntegration = baseVercelAiIntegration(options);\n\n return extendIntegration(parentIntegration, {\n options,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n waitForTracingChannelBinding(() => {\n subscribeVercelAiOrchestrionChannels(dc.tracingChannel, options);\n });\n },\n });\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK. Supported are:\n * - v7 via native `ai:telemetry` tracing channel\n * - v6 via orchestrion `orchestrion:ai:*` channels\n */\nexport const vercelAiChannelIntegration = defineIntegration(_vercelAiChannelIntegration);\n"],"names":["baseVercelAiIntegration","extendIntegration","dc","waitForTracingChannelBinding","subscribeVercelAiOrchestrionChannels","defineIntegration"],"mappings":";;;;;;;AAgBA,MAAM,2BAAA,IAA+B,CAAC,OAAA,GAA2B,EAAC,KAAM;AACtE,EAAA,MAAM,iBAAA,GAAoBA,0BAAwB,OAAO,CAAA;AAEzD,EAAA,OAAOC,uBAAkB,iBAAA,EAAmB;AAAA,IAC1C,OAAA;AAAA,IACA,SAAA,GAAY;AAEV,MAAA,IAAI,CAACC,mBAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAEA,MAAAC,iCAAA,CAA6B,MAAM;AACjC,QAAAC,oEAAA,CAAqCF,kBAAA,CAAG,gBAAgB,OAAO,CAAA;AAAA,MACjE,CAAC,CAAA;AAAA,IACH;AAAA,GACD,CAAA;AACH,CAAA,CAAA;AAOO,MAAM,0BAAA,GAA6BG,uBAAkB,2BAA2B;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const core = require('@sentry/core'); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const mongooseDcSubscriber = require('./mongoose-dc-subscriber.js'); | ||
| const _mongooseIntegration = (() => { | ||
| return { | ||
| name: "Mongoose", | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| core.waitForTracingChannelBinding(() => { | ||
| mongooseDcSubscriber.subscribeMongooseDiagnosticChannels(diagnosticsChannel.tracingChannel); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const mongooseIntegration = core.defineIntegration(_mongooseIntegration); | ||
| exports.mongooseIntegration = mongooseIntegration; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../src/mongoose/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn, waitForTracingChannelBinding } from '@sentry/core';\nimport * as dc from 'node:diagnostics_channel';\nimport { subscribeMongooseDiagnosticChannels } from './mongoose-dc-subscriber';\n\nconst _mongooseIntegration = (() => {\n return {\n name: 'Mongoose',\n setupOnce() {\n // Bail on Node <= 18.18.0, where `tracingChannel` does not exist.\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to mongoose's native tracing channels (mongoose >= 9.7).\n // This is a no-op on versions that don't publish to the channels, so it is always safe to call.\n waitForTracingChannelBinding(() => {\n subscribeMongooseDiagnosticChannels(dc.tracingChannel);\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the [mongoose](https://www.npmjs.com/package/mongoose) library via its native\n * `node:diagnostics_channel` tracing channels (mongoose >= 9.7).\n *\n * On older mongoose versions the channels are never published to, so this integration is inert and\n * the IITM-based patcher (gated to `< 9.7.0`) handles instrumentation instead.\n */\nexport const mongooseIntegration = defineIntegration(_mongooseIntegration);\n"],"names":["dc","waitForTracingChannelBinding","subscribeMongooseDiagnosticChannels","defineIntegration"],"mappings":";;;;;;AAIA,MAAM,wBAAwB,MAAM;AAClC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAACA,mBAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAIA,MAAAC,iCAAA,CAA6B,MAAM;AACjC,QAAAC,wDAAA,CAAoCF,mBAAG,cAAc,CAAA;AAAA,MACvD,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AASO,MAAM,mBAAA,GAAsBG,uBAAkB,oBAAoB;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../debug-build.js'); | ||
| const tracingChannel = require('../tracing-channel.js'); | ||
| const MONGOOSE_DC_CHANNEL_QUERY = "mongoose:query"; | ||
| const MONGOOSE_DC_CHANNEL_AGGREGATE = "mongoose:aggregate"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_SAVE = "mongoose:model:save"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = "mongoose:model:insertMany"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = "mongoose:model:bulkWrite"; | ||
| const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = "mongoose:cursor:next"; | ||
| const ORIGIN = "auto.db.mongoose.diagnostic_channel"; | ||
| const DB_SYSTEM_NAME_VALUE_MONGODB = "mongodb"; | ||
| const MAX_REDACTION_DEPTH = 10; | ||
| let subscribed = false; | ||
| function subscribeMongooseDiagnosticChannels(tracingChannel) { | ||
| if (subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| try { | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_QUERY); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_AGGREGATE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_SAVE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_CURSOR_NEXT); | ||
| } catch { | ||
| debugBuild.DEBUG_BUILD && core.debug.log("Mongoose node:diagnostics_channel subscription failed."); | ||
| } | ||
| } | ||
| function setupChannel(tracingChannel$1, channelName) { | ||
| tracingChannel.bindTracingChannelToSpan(tracingChannel$1(channelName), (data) => { | ||
| const collection = data.collection; | ||
| const queryText = redactMongoQuery(data.args?.pipeline ?? data.args?.filter); | ||
| const batchSize = getBatchSize(data); | ||
| return core.startInactiveSpan({ | ||
| name: collection ? `mongoose.${collection}.${data.operation}` : `mongoose.${data.operation}`, | ||
| attributes: { | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_OP]: "db", | ||
| [attributes.DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_MONGODB, | ||
| [attributes.DB_OPERATION_NAME]: data.operation, | ||
| [attributes.DB_COLLECTION_NAME]: collection ?? void 0, | ||
| [attributes.DB_NAMESPACE]: data.database ?? void 0, | ||
| [attributes.DB_QUERY_TEXT]: queryText ?? void 0, | ||
| [attributes.DB_OPERATION_BATCH_SIZE]: batchSize ?? void 0, | ||
| [attributes.SERVER_ADDRESS]: data.serverAddress ?? void 0, | ||
| [attributes.SERVER_PORT]: data.serverPort ?? void 0 | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
| function getBatchSize(data) { | ||
| const args = data.args; | ||
| const batch = data.operation === "insertMany" ? args?.docs : data.operation === "bulkWrite" ? args?.ops : void 0; | ||
| return Array.isArray(batch) && batch.length > 1 ? batch.length : void 0; | ||
| } | ||
| function redactMongoQuery(value) { | ||
| if (value == null) { | ||
| return void 0; | ||
| } | ||
| try { | ||
| const redacted = redactValue(value, 0); | ||
| const text = JSON.stringify(redacted); | ||
| return text == null || text === "{}" || text === "[]" ? void 0 : text; | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| function redactValue(value, depth) { | ||
| if (depth > MAX_REDACTION_DEPTH) { | ||
| return "?"; | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.map((item) => redactValue(item, depth + 1)); | ||
| } | ||
| if (value && typeof value === "object") { | ||
| const out = {}; | ||
| for (const key of Object.keys(value)) { | ||
| out[key] = redactValue(value[key], depth + 1); | ||
| } | ||
| return out; | ||
| } | ||
| return "?"; | ||
| } | ||
| exports.MONGOOSE_DC_CHANNEL_AGGREGATE = MONGOOSE_DC_CHANNEL_AGGREGATE; | ||
| exports.MONGOOSE_DC_CHANNEL_CURSOR_NEXT = MONGOOSE_DC_CHANNEL_CURSOR_NEXT; | ||
| exports.MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE; | ||
| exports.MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY; | ||
| exports.MONGOOSE_DC_CHANNEL_MODEL_SAVE = MONGOOSE_DC_CHANNEL_MODEL_SAVE; | ||
| exports.MONGOOSE_DC_CHANNEL_QUERY = MONGOOSE_DC_CHANNEL_QUERY; | ||
| exports.subscribeMongooseDiagnosticChannels = subscribeMongooseDiagnosticChannels; | ||
| //# sourceMappingURL=mongoose-dc-subscriber.js.map |
| {"version":3,"file":"mongoose-dc-subscriber.js","sources":["../../../src/mongoose/mongoose-dc-subscriber.ts"],"sourcesContent":["import type { TracingChannel } from 'node:diagnostics_channel';\nimport {\n DB_COLLECTION_NAME,\n DB_NAMESPACE,\n DB_OPERATION_BATCH_SIZE,\n DB_OPERATION_NAME,\n DB_QUERY_TEXT,\n DB_SYSTEM_NAME,\n SERVER_ADDRESS,\n SERVER_PORT,\n} from '@sentry/conventions/attributes';\nimport { debug, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n// Channel names published by mongoose >= 9.7.0 (see mongoose `lib/tracing.js`,\n// `lib/query.js`, `lib/aggregate.js`, `lib/model.js` and `lib/cursor/*`).\n// Hardcoded so the subscriber does not have to import mongoose — the channels\n// just have to be subscribed to before the user's mongoose code publishes.\nexport const MONGOOSE_DC_CHANNEL_QUERY = 'mongoose:query';\nexport const MONGOOSE_DC_CHANNEL_AGGREGATE = 'mongoose:aggregate';\nexport const MONGOOSE_DC_CHANNEL_MODEL_SAVE = 'mongoose:model:save';\nexport const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = 'mongoose:model:insertMany';\nexport const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = 'mongoose:model:bulkWrite';\nexport const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = 'mongoose:cursor:next';\n\nconst ORIGIN = 'auto.db.mongoose.diagnostic_channel';\nconst DB_SYSTEM_NAME_VALUE_MONGODB = 'mongodb';\n\n// Cap recursion so a self-referential or pathologically deep query can never\n// stall (or blow the stack in) instrumentation.\nconst MAX_REDACTION_DEPTH = 10;\n\n/**\n * Shape of the context object mongoose >= 9.7.0 publishes on its tracing\n * channels (mongoose's `TracingContext`, see `types/tracing.d.ts`).\n *\n * Node's `tracePromise` mutates this same object with `result`/`error` once the\n * operation settles, which `bindTracingChannelToSpan` reads in its lifecycle\n * handlers — hence both are declared optional here.\n *\n * Unlike redis/ioredis, mongoose does NOT pre-sanitize the payload, so `args`\n * carries the raw user query. We redact it before emitting `db.query.text`.\n */\nexport interface MongooseTracingData {\n operation: string;\n /** Absent for connection-level `aggregate()` calls, which have no model/collection. */\n collection?: string;\n database?: string;\n serverAddress?: string;\n serverPort?: number;\n /** Cursor channels only: the cursor's fetch batch size and tailable flag. */\n batchSize?: number;\n tailable?: boolean;\n /**\n * Operation-specific arguments. `filter` (queries/cursors) and `pipeline`\n * (aggregations) carry the query shape; `docs`/`ops` carry batch payloads.\n */\n args?: {\n filter?: unknown;\n pipeline?: unknown;\n docs?: unknown;\n ops?: unknown;\n [key: string]: unknown;\n };\n result?: unknown;\n error?: Error;\n}\n\n/**\n * Platform-provided factory that creates a native tracing channel for the given name. The\n * subscriber binds the span and its lifecycle onto the channel via `bindTracingChannelToSpan`,\n * which propagates the active span through the runtime's async context.\n *\n * Node passes `node:diagnostics_channel`'s `tracingChannel` directly.\n */\nexport type MongooseTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to mongoose's diagnostics-channel events\n * (`mongoose:query`, `:aggregate`, `:model:save`, `:model:insertMany`,\n * `:model:bulkWrite`, `:cursor:next`), published by mongoose >= 9.7.0.\n *\n * On older mongoose versions the channels are never published to, so the\n * subscribers are inert — there is no double-instrumentation against the\n * IITM-based vendored patcher, which is gated to `< 9.7.0`.\n *\n * Idempotent: subsequent calls are a no-op.\n */\nexport function subscribeMongooseDiagnosticChannels(tracingChannel: MongooseTracingChannelFactory): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n try {\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_QUERY);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_AGGREGATE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_SAVE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_CURSOR_NEXT);\n } catch {\n // The factory relies on `node:diagnostics_channel`, which isn't always\n // available. Fail closed; the SDK simply won't emit mongoose spans here.\n DEBUG_BUILD && debug.log('Mongoose node:diagnostics_channel subscription failed.');\n }\n}\n\nfunction setupChannel(tracingChannel: MongooseTracingChannelFactory, channelName: string): void {\n bindTracingChannelToSpan(tracingChannel<MongooseTracingData>(channelName), data => {\n const collection = data.collection;\n const queryText = redactMongoQuery(data.args?.pipeline ?? data.args?.filter);\n const batchSize = getBatchSize(data);\n\n return startInactiveSpan({\n name: collection ? `mongoose.${collection}.${data.operation}` : `mongoose.${data.operation}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db',\n [DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_MONGODB,\n [DB_OPERATION_NAME]: data.operation,\n [DB_COLLECTION_NAME]: collection ?? undefined,\n [DB_NAMESPACE]: data.database ?? undefined,\n [DB_QUERY_TEXT]: queryText ?? undefined,\n [DB_OPERATION_BATCH_SIZE]: batchSize ?? undefined,\n [SERVER_ADDRESS]: data.serverAddress ?? undefined,\n [SERVER_PORT]: data.serverPort ?? undefined,\n },\n });\n });\n}\n\n/**\n * `db.operation.batch.size` is only meaningful for genuine batch operations.\n * Mongoose's cursor `batchSize` is a fetch-tuning option, not a batch operation\n * size, so it is intentionally excluded here.\n */\nfunction getBatchSize(data: MongooseTracingData): number | undefined {\n const args = data.args;\n const batch = data.operation === 'insertMany' ? args?.docs : data.operation === 'bulkWrite' ? args?.ops : undefined;\n\n return Array.isArray(batch) && batch.length > 1 ? batch.length : undefined;\n}\n\n/**\n * Serialize a mongoose filter/pipeline into `db.query.text` while stripping every\n * value: keys and Mongo operators (`$gt`, `$in`, …) are preserved, leaf values\n * become `'?'`. Mongoose does not sanitize its channel payload, so this prevents\n * raw user data (potential PII) from leaving the process. Returns `undefined`\n * (rather than throwing) on anything it cannot serialize.\n */\nfunction redactMongoQuery(value: unknown): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n try {\n const redacted = redactValue(value, 0);\n const text = JSON.stringify(redacted);\n\n // Skip empty/uninformative shapes (e.g. a `findOne()` with no filter).\n return text == null || text === '{}' || text === '[]' ? undefined : text;\n } catch {\n return undefined;\n }\n}\n\nfunction redactValue(value: unknown, depth: number): unknown {\n if (depth > MAX_REDACTION_DEPTH) {\n return '?';\n }\n\n if (Array.isArray(value)) {\n return value.map(item => redactValue(item, depth + 1));\n }\n\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>)) {\n out[key] = redactValue((value as Record<string, unknown>)[key], depth + 1);\n }\n\n return out;\n }\n\n return '?';\n}\n"],"names":["DEBUG_BUILD","debug","tracingChannel","bindTracingChannelToSpan","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","SEMANTIC_ATTRIBUTE_SENTRY_OP","DB_SYSTEM_NAME","DB_OPERATION_NAME","DB_COLLECTION_NAME","DB_NAMESPACE","DB_QUERY_TEXT","DB_OPERATION_BATCH_SIZE","SERVER_ADDRESS","SERVER_PORT"],"mappings":";;;;;;;AAmBO,MAAM,yBAAA,GAA4B;AAClC,MAAM,6BAAA,GAAgC;AACtC,MAAM,8BAAA,GAAiC;AACvC,MAAM,qCAAA,GAAwC;AAC9C,MAAM,oCAAA,GAAuC;AAC7C,MAAM,+BAAA,GAAkC;AAE/C,MAAM,MAAA,GAAS,qCAAA;AACf,MAAM,4BAAA,GAA+B,SAAA;AAIrC,MAAM,mBAAA,GAAsB,EAAA;AA+C5B,IAAI,UAAA,GAAa,KAAA;AAaV,SAAS,oCAAoC,cAAA,EAAqD;AACvG,EAAA,IAAI,UAAA,EAAY;AACd,IAAA;AAAA,EACF;AACA,EAAA,UAAA,GAAa,IAAA;AAEb,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,gBAAgB,yBAAyB,CAAA;AACtD,IAAA,YAAA,CAAa,gBAAgB,6BAA6B,CAAA;AAC1D,IAAA,YAAA,CAAa,gBAAgB,8BAA8B,CAAA;AAC3D,IAAA,YAAA,CAAa,gBAAgB,qCAAqC,CAAA;AAClE,IAAA,YAAA,CAAa,gBAAgB,oCAAoC,CAAA;AACjE,IAAA,YAAA,CAAa,gBAAgB,+BAA+B,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAGN,IAAAA,sBAAA,IAAeC,UAAA,CAAM,IAAI,wDAAwD,CAAA;AAAA,EACnF;AACF;AAEA,SAAS,YAAA,CAAaC,kBAA+C,WAAA,EAA2B;AAC9F,EAAAC,uCAAA,CAAyBD,gBAAA,CAAoC,WAAW,CAAA,EAAG,CAAA,IAAA,KAAQ;AACjF,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,YAAY,gBAAA,CAAiB,IAAA,CAAK,MAAM,QAAA,IAAY,IAAA,CAAK,MAAM,MAAM,CAAA;AAC3E,IAAA,MAAM,SAAA,GAAY,aAAa,IAAI,CAAA;AAEnC,IAAA,OAAOE,sBAAA,CAAkB;AAAA,MACvB,IAAA,EAAM,UAAA,GAAa,CAAA,SAAA,EAAY,UAAU,CAAA,CAAA,EAAI,KAAK,SAAS,CAAA,CAAA,GAAK,CAAA,SAAA,EAAY,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,MAC1F,UAAA,EAAY;AAAA,QACV,CAACC,qCAAgC,GAAG,MAAA;AAAA,QACpC,CAACC,iCAA4B,GAAG,IAAA;AAAA,QAChC,CAACC,yBAAc,GAAG,4BAAA;AAAA,QAClB,CAACC,4BAAiB,GAAG,IAAA,CAAK,SAAA;AAAA,QAC1B,CAACC,6BAAkB,GAAG,UAAA,IAAc,MAAA;AAAA,QACpC,CAACC,uBAAY,GAAG,IAAA,CAAK,QAAA,IAAY,MAAA;AAAA,QACjC,CAACC,wBAAa,GAAG,SAAA,IAAa,MAAA;AAAA,QAC9B,CAACC,kCAAuB,GAAG,SAAA,IAAa,MAAA;AAAA,QACxC,CAACC,yBAAc,GAAG,IAAA,CAAK,aAAA,IAAiB,MAAA;AAAA,QACxC,CAACC,sBAAW,GAAG,IAAA,CAAK,UAAA,IAAc;AAAA;AACpC,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAOA,SAAS,aAAa,IAAA,EAA+C;AACnE,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,KAAc,YAAA,GAAe,IAAA,EAAM,OAAO,IAAA,CAAK,SAAA,KAAc,WAAA,GAAc,IAAA,EAAM,GAAA,GAAM,MAAA;AAE1G,EAAA,OAAO,KAAA,CAAM,QAAQ,KAAK,CAAA,IAAK,MAAM,MAAA,GAAS,CAAA,GAAI,MAAM,MAAA,GAAS,MAAA;AACnE;AASA,SAAS,iBAAiB,KAAA,EAAoC;AAC5D,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,KAAA,EAAO,CAAC,CAAA;AACrC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA;AAGpC,IAAA,OAAO,QAAQ,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,OAAO,KAAA,CAAA,GAAY,IAAA;AAAA,EACtE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAA,CAAY,OAAgB,KAAA,EAAwB;AAC3D,EAAA,IAAI,QAAQ,mBAAA,EAAqB;AAC/B,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,MAAM,GAAA,CAAI,CAAA,IAAA,KAAQ,YAAY,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,EACvD;AAEA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,KAAgC,CAAA,EAAG;AAC/D,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,WAAA,CAAa,MAAkC,GAAG,CAAA,EAAG,QAAQ,CAAC,CAAA;AAAA,IAC3E;AAEA,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,OAAO,GAAA;AACT;;;;;;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const anthropicAiConfig = [ | ||
| // One entry each for CJS/ESM | ||
| ...["resources/messages/messages.js", "resources/messages/messages.mjs"].flatMap( | ||
| (filePath) => ["create", "countTokens"].map((methodName) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName, kind: "Auto" } | ||
| })) | ||
| ), | ||
| ...["resources/completions.js", "resources/completions.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Completions", methodName: "create", kind: "Auto" } | ||
| })), | ||
| ...["resources/beta/messages/messages.js", "resources/beta/messages/messages.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName: "create", kind: "Auto" } | ||
| })), | ||
| ...["resources/models.js", "resources/models.mjs"].map((filePath) => ({ | ||
| channelName: "models", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Models", methodName: "retrieve", kind: "Auto" } | ||
| })), | ||
| // `messages.stream()` returns a synchronous emitter, not a promise, so `kind: 'Sync'` is required: | ||
| // `Auto`'s promise wrapper never publishes `end` for a non-thenable return, so the span would never end. | ||
| ...["resources/messages/messages.js", "resources/messages/messages.mjs"].map((filePath) => ({ | ||
| channelName: "messages-stream", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName: "stream", kind: "Sync" } | ||
| })) | ||
| ]; | ||
| const anthropicAiChannels = { | ||
| ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat", | ||
| ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models", | ||
| ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream" | ||
| }; | ||
| exports.anthropicAiChannels = anthropicAiChannels; | ||
| exports.anthropicAiConfig = anthropicAiConfig; | ||
| //# sourceMappingURL=anthropic-ai.js.map |
| {"version":3,"file":"anthropic-ai.js","sources":["../../../../src/orchestrion/config/anthropic-ai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const anthropicAiConfig = [\n // One entry each for CJS/ESM\n ...['resources/messages/messages.js', 'resources/messages/messages.mjs'].flatMap(filePath =>\n (['create', 'countTokens'] as const).map(methodName => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName, kind: 'Auto' as const },\n })),\n ),\n ...['resources/completions.js', 'resources/completions.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Completions', methodName: 'create', kind: 'Auto' as const },\n })),\n ...['resources/beta/messages/messages.js', 'resources/beta/messages/messages.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName: 'create', kind: 'Auto' as const },\n })),\n ...['resources/models.js', 'resources/models.mjs'].map(filePath => ({\n channelName: 'models',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Models', methodName: 'retrieve', kind: 'Auto' as const },\n })),\n // `messages.stream()` returns a synchronous emitter, not a promise, so `kind: 'Sync'` is required:\n // `Auto`'s promise wrapper never publishes `end` for a non-thenable return, so the span would never end.\n ...['resources/messages/messages.js', 'resources/messages/messages.mjs'].map(filePath => ({\n channelName: 'messages-stream',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName: 'stream', kind: 'Sync' as const },\n })),\n] satisfies InstrumentationConfig[];\n\nexport const anthropicAiChannels = {\n ANTHROPIC_CHAT: 'orchestrion:@anthropic-ai/sdk:chat',\n ANTHROPIC_MODELS: 'orchestrion:@anthropic-ai/sdk:models',\n ANTHROPIC_MESSAGES_STREAM: 'orchestrion:@anthropic-ai/sdk:messages-stream',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,iBAAA,GAAoB;AAAA;AAAA,EAE/B,GAAG,CAAC,gCAAA,EAAkC,iCAAiC,CAAA,CAAE,OAAA;AAAA,IAAQ,cAC9E,CAAC,QAAA,EAAU,aAAa,CAAA,CAAY,IAAI,CAAA,UAAA,MAAe;AAAA,MACtD,WAAA,EAAa,MAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,MAC3E,eAAe,EAAE,SAAA,EAAW,UAAA,EAAY,UAAA,EAAY,MAAM,MAAA;AAAgB,KAC5E,CAAE;AAAA,GACJ;AAAA,EACA,GAAG,CAAC,0BAAA,EAA4B,2BAA2B,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5E,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,eAAe,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACzF,CAAE,CAAA;AAAA,EACF,GAAG,CAAC,qCAAA,EAAuC,sCAAsC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAClG,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,YAAY,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACtF,CAAE,CAAA;AAAA,EACF,GAAG,CAAC,qBAAA,EAAuB,sBAAsB,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAClE,WAAA,EAAa,QAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,UAAA,EAAY,MAAM,MAAA;AAAgB,GACtF,CAAE,CAAA;AAAA;AAAA;AAAA,EAGF,GAAG,CAAC,gCAAA,EAAkC,iCAAiC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IACxF,WAAA,EAAa,iBAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,YAAY,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACtF,CAAE;AACJ;AAEO,MAAM,mBAAA,GAAsB;AAAA,EACjC,cAAA,EAAgB,oCAAA;AAAA,EAChB,gBAAA,EAAkB,sCAAA;AAAA,EAClB,yBAAA,EAA2B;AAC7B;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const hapiConfig = [ | ||
| // hapi's `route`/`ext` live on an anonymous class (`internals.Server = class {}`), | ||
| // so `{className}` can't match — `{methodName}` targets them in lib/server.js. Both | ||
| // are synchronous void methods, so `Sync` suffices: we only use `start` to swap | ||
| // handlers in `ctx.arguments`. Shape verified across the whole range. | ||
| { | ||
| channelName: "route", | ||
| module: { name: "@hapi/hapi", versionRange: ">=17.0.0 <22.0.0", filePath: "lib/server.js" }, | ||
| functionQuery: { methodName: "route", kind: "Sync" } | ||
| }, | ||
| { | ||
| channelName: "ext", | ||
| module: { name: "@hapi/hapi", versionRange: ">=17.0.0 <22.0.0", filePath: "lib/server.js" }, | ||
| functionQuery: { methodName: "ext", kind: "Sync" } | ||
| } | ||
| ]; | ||
| const hapiChannels = { | ||
| HAPI_ROUTE: "orchestrion:@hapi/hapi:route", | ||
| HAPI_EXT: "orchestrion:@hapi/hapi:ext" | ||
| }; | ||
| exports.hapiChannels = hapiChannels; | ||
| exports.hapiConfig = hapiConfig; | ||
| //# sourceMappingURL=hapi.js.map |
| {"version":3,"file":"hapi.js","sources":["../../../../src/orchestrion/config/hapi.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const hapiConfig = [\n // hapi's `route`/`ext` live on an anonymous class (`internals.Server = class {}`),\n // so `{className}` can't match — `{methodName}` targets them in lib/server.js. Both\n // are synchronous void methods, so `Sync` suffices: we only use `start` to swap\n // handlers in `ctx.arguments`. Shape verified across the whole range.\n {\n channelName: 'route',\n module: { name: '@hapi/hapi', versionRange: '>=17.0.0 <22.0.0', filePath: 'lib/server.js' },\n functionQuery: { methodName: 'route', kind: 'Sync' },\n },\n {\n channelName: 'ext',\n module: { name: '@hapi/hapi', versionRange: '>=17.0.0 <22.0.0', filePath: 'lib/server.js' },\n functionQuery: { methodName: 'ext', kind: 'Sync' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const hapiChannels = {\n HAPI_ROUTE: 'orchestrion:@hapi/hapi:route',\n HAPI_EXT: 'orchestrion:@hapi/hapi:ext',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,cAAc,YAAA,EAAc,kBAAA,EAAoB,UAAU,eAAA,EAAgB;AAAA,IAC1F,aAAA,EAAe,EAAE,UAAA,EAAY,OAAA,EAAS,MAAM,MAAA;AAAO,GACrD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,KAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,cAAc,YAAA,EAAc,kBAAA,EAAoB,UAAU,eAAA,EAAgB;AAAA,IAC1F,aAAA,EAAe,EAAE,UAAA,EAAY,KAAA,EAAO,MAAM,MAAA;AAAO;AAErD;AAEO,MAAM,YAAA,GAAe;AAAA,EAC1B,UAAA,EAAY,8BAAA;AAAA,EACZ,QAAA,EAAU;AACZ;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const mysql = require('./mysql.js'); | ||
| const lruMemoizer = require('./lru-memoizer.js'); | ||
| const ioredis = require('./ioredis.js'); | ||
| const openai = require('./openai.js'); | ||
| const pg = require('./pg.js'); | ||
| const anthropicAi = require('./anthropic-ai.js'); | ||
| const vercelAi = require('./vercel-ai.js'); | ||
| const hapi = require('./hapi.js'); | ||
| const SENTRY_INSTRUMENTATIONS = [ | ||
| ...mysql.mysqlConfig, | ||
| ...lruMemoizer.lruMemoizerConfig, | ||
| ...ioredis.ioredisConfig, | ||
| ...openai.openaiConfig, | ||
| ...pg.pgConfig, | ||
| ...anthropicAi.anthropicAiConfig, | ||
| ...vercelAi.vercelAiConfig, | ||
| ...hapi.hapiConfig | ||
| ]; | ||
| const INSTRUMENTED_MODULE_NAMES = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map((i) => i.module.name))); | ||
| function withoutInstrumentedExternals(external) { | ||
| if (!external) { | ||
| return void 0; | ||
| } | ||
| return external.filter( | ||
| (entry) => !INSTRUMENTED_MODULE_NAMES.some((name) => entry === name || entry.startsWith(`${name}/`)) | ||
| ); | ||
| } | ||
| exports.INSTRUMENTED_MODULE_NAMES = INSTRUMENTED_MODULE_NAMES; | ||
| exports.SENTRY_INSTRUMENTATIONS = SENTRY_INSTRUMENTATIONS; | ||
| exports.withoutInstrumentedExternals = withoutInstrumentedExternals; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../../src/orchestrion/config/index.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\nimport { mysqlConfig } from './mysql';\nimport { lruMemoizerConfig } from './lru-memoizer';\nimport { ioredisConfig } from './ioredis';\nimport { openaiConfig } from './openai';\nimport { pgConfig } from './pg';\nimport { anthropicAiConfig } from './anthropic-ai';\nimport { vercelAiConfig } from './vercel-ai';\nimport { hapiConfig } from './hapi';\n\nexport const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[] = [\n ...mysqlConfig,\n ...lruMemoizerConfig,\n ...ioredisConfig,\n ...openaiConfig,\n ...pgConfig,\n ...anthropicAiConfig,\n ...vercelAiConfig,\n ...hapiConfig,\n];\n\n/**\n * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS`\n * (e.g. `['mysql']`).\n *\n * Bundler plugins MUST ensure these are actually bundled rather than\n * externalized: an externalized dependency is resolved from `node_modules` at\n * runtime and never passes through the code transform's `onLoad`, so its\n * diagnostics_channel calls are silently never injected.\n */\nexport const INSTRUMENTED_MODULE_NAMES: string[] = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map(i => i.module.name)));\n\n/**\n * Returns `external` with any instrumented packages removed, so a bundler that\n * uses an \"external\" denylist (esbuild, Bun, Rollup) still bundles — and thus\n * transforms — them. Matches an exact package name (`'mysql'`) or a subpath\n * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined`\n * is returned unchanged.\n *\n * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes\n * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.)\n */\nexport function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined {\n if (!external) {\n return undefined;\n }\n return external.filter(\n entry => !INSTRUMENTED_MODULE_NAMES.some(name => entry === name || entry.startsWith(`${name}/`)),\n );\n}\n"],"names":["mysqlConfig","lruMemoizerConfig","ioredisConfig","openaiConfig","pgConfig","anthropicAiConfig","vercelAiConfig","hapiConfig"],"mappings":";;;;;;;;;;;AAUO,MAAM,uBAAA,GAAmD;AAAA,EAC9D,GAAGA,iBAAA;AAAA,EACH,GAAGC,6BAAA;AAAA,EACH,GAAGC,qBAAA;AAAA,EACH,GAAGC,mBAAA;AAAA,EACH,GAAGC,WAAA;AAAA,EACH,GAAGC,6BAAA;AAAA,EACH,GAAGC,uBAAA;AAAA,EACH,GAAGC;AACL;AAWO,MAAM,yBAAA,GAAsC,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,uBAAA,CAAwB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,CAAO,IAAI,CAAC,CAAC;AAY/G,SAAS,6BAA6B,QAAA,EAA+D;AAC1G,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAA,KAAA,KAAS,CAAC,yBAAA,CAA0B,IAAA,CAAK,CAAA,IAAA,KAAQ,KAAA,KAAU,IAAA,IAAQ,KAAA,CAAM,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAC;AAAA,GACjG;AACF;;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const ioredisConfig = [ | ||
| // ioredis `<5.11.0` (>=5.11.0 publishes its own `ioredis:*` diagnostics_channel) | ||
| ...["lib/redis.js", "built/redis.js", "built/redis/index.js"].flatMap((filePath) => [ | ||
| { | ||
| channelName: "command", | ||
| module: { name: "ioredis", versionRange: ">=2.0.0 <5.0.0", filePath }, | ||
| functionQuery: { expressionName: "sendCommand", kind: "Async" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "ioredis", versionRange: ">=2.0.0 <5.0.0", filePath }, | ||
| functionQuery: { expressionName: "connect", kind: "Async" } | ||
| } | ||
| ]), | ||
| { | ||
| channelName: "command", | ||
| module: { name: "ioredis", versionRange: ">=5.0.0 <5.11.0", filePath: "built/Redis.js" }, | ||
| functionQuery: { className: "Redis", methodName: "sendCommand", kind: "Async" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "ioredis", versionRange: ">=5.0.0 <5.11.0", filePath: "built/Redis.js" }, | ||
| functionQuery: { className: "Redis", methodName: "connect", kind: "Async" } | ||
| } | ||
| ]; | ||
| const ioredisChannels = { | ||
| IOREDIS_COMMAND: "orchestrion:ioredis:command", | ||
| IOREDIS_CONNECT: "orchestrion:ioredis:connect" | ||
| }; | ||
| exports.ioredisChannels = ioredisChannels; | ||
| exports.ioredisConfig = ioredisConfig; | ||
| //# sourceMappingURL=ioredis.js.map |
| {"version":3,"file":"ioredis.js","sources":["../../../../src/orchestrion/config/ioredis.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const ioredisConfig = [\n // ioredis `<5.11.0` (>=5.11.0 publishes its own `ioredis:*` diagnostics_channel)\n ...['lib/redis.js', 'built/redis.js', 'built/redis/index.js'].flatMap((filePath): InstrumentationConfig[] => [\n {\n channelName: 'command',\n module: { name: 'ioredis', versionRange: '>=2.0.0 <5.0.0', filePath },\n functionQuery: { expressionName: 'sendCommand', kind: 'Async' },\n },\n {\n channelName: 'connect',\n module: { name: 'ioredis', versionRange: '>=2.0.0 <5.0.0', filePath },\n functionQuery: { expressionName: 'connect', kind: 'Async' },\n },\n ]),\n {\n channelName: 'command',\n module: { name: 'ioredis', versionRange: '>=5.0.0 <5.11.0', filePath: 'built/Redis.js' },\n functionQuery: { className: 'Redis', methodName: 'sendCommand', kind: 'Async' },\n },\n {\n channelName: 'connect',\n module: { name: 'ioredis', versionRange: '>=5.0.0 <5.11.0', filePath: 'built/Redis.js' },\n functionQuery: { className: 'Redis', methodName: 'connect', kind: 'Async' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const ioredisChannels = {\n IOREDIS_COMMAND: 'orchestrion:ioredis:command',\n IOREDIS_CONNECT: 'orchestrion:ioredis:connect',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,GAAG,CAAC,cAAA,EAAgB,gBAAA,EAAkB,sBAAsB,CAAA,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAsC;AAAA,IAC3G;AAAA,MACE,WAAA,EAAa,SAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,MACpE,aAAA,EAAe,EAAE,cAAA,EAAgB,aAAA,EAAe,MAAM,OAAA;AAAQ,KAChE;AAAA,IACA;AAAA,MACE,WAAA,EAAa,SAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,MACpE,aAAA,EAAe,EAAE,cAAA,EAAgB,SAAA,EAAW,MAAM,OAAA;AAAQ;AAC5D,GACD,CAAA;AAAA,EACD;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,iBAAA,EAAmB,UAAU,gBAAA,EAAiB;AAAA,IACvF,eAAe,EAAE,SAAA,EAAW,SAAS,UAAA,EAAY,aAAA,EAAe,MAAM,OAAA;AAAQ,GAChF;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,iBAAA,EAAmB,UAAU,gBAAA,EAAiB;AAAA,IACvF,eAAe,EAAE,SAAA,EAAW,SAAS,UAAA,EAAY,SAAA,EAAW,MAAM,OAAA;AAAQ;AAE9E;AAEO,MAAM,eAAA,GAAkB;AAAA,EAC7B,eAAA,EAAiB,6BAAA;AAAA,EACjB,eAAA,EAAiB;AACnB;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const lruMemoizerConfig = [ | ||
| { | ||
| channelName: "load", | ||
| // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0 | ||
| module: { name: "lru-memoizer", versionRange: ">=2.1.0 <4", filePath: "lib/async.js" }, | ||
| functionQuery: { functionName: "memoizedFunction", kind: "Callback" } | ||
| } | ||
| ]; | ||
| const lruMemoizerChannels = { | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| }; | ||
| exports.lruMemoizerChannels = lruMemoizerChannels; | ||
| exports.lruMemoizerConfig = lruMemoizerConfig; | ||
| //# sourceMappingURL=lru-memoizer.js.map |
| {"version":3,"file":"lru-memoizer.js","sources":["../../../../src/orchestrion/config/lru-memoizer.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const lruMemoizerConfig = [\n {\n channelName: 'load',\n // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0\n module: { name: 'lru-memoizer', versionRange: '>=2.1.0 <4', filePath: 'lib/async.js' },\n functionQuery: { functionName: 'memoizedFunction', kind: 'Callback' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const lruMemoizerChannels = {\n LRU_MEMOIZER_LOAD: 'orchestrion:lru-memoizer:load',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,iBAAA,GAAoB;AAAA,EAC/B;AAAA,IACE,WAAA,EAAa,MAAA;AAAA;AAAA,IAEb,QAAQ,EAAE,IAAA,EAAM,gBAAgB,YAAA,EAAc,YAAA,EAAc,UAAU,cAAA,EAAe;AAAA,IACrF,aAAA,EAAe,EAAE,YAAA,EAAc,kBAAA,EAAoB,MAAM,UAAA;AAAW;AAExE;AAEO,MAAM,mBAAA,GAAsB;AAAA,EACjC,iBAAA,EAAmB;AACrB;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const mysqlConfig = [ | ||
| { | ||
| channelName: "query", | ||
| module: { name: "mysql", versionRange: ">=2.0.0 <3", filePath: "lib/Connection.js" }, | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| } | ||
| ]; | ||
| const mysqlChannels = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query" | ||
| }; | ||
| exports.mysqlChannels = mysqlChannels; | ||
| exports.mysqlConfig = mysqlConfig; | ||
| //# sourceMappingURL=mysql.js.map |
| {"version":3,"file":"mysql.js","sources":["../../../../src/orchestrion/config/mysql.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const mysqlConfig = [\n {\n channelName: 'query',\n module: { name: 'mysql', versionRange: '>=2.0.0 <3', filePath: 'lib/Connection.js' },\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const mysqlChannels = {\n MYSQL_QUERY: 'orchestrion:mysql:query',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,WAAA,GAAc;AAAA,EACzB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,SAAS,YAAA,EAAc,YAAA,EAAc,UAAU,mBAAA,EAAoB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO;AAE3D;AAEO,MAAM,aAAA,GAAgB;AAAA,EAC3B,WAAA,EAAa;AACf;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const openaiConfig = [ | ||
| // OpenAI chat completions. `Completions.create` returns a thenable `APIPromise` with no callback arg, | ||
| // so `kind: 'Auto'` resolves to `wrapPromise`. openai ships dual CJS/ESM and the matcher compares | ||
| // `filePath` exactly, hence one entry per built file (`.js` for `require`, `.mjs` for `import`). | ||
| ...["resources/chat/completions/completions.js", "resources/chat/completions/completions.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Completions", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI responses API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/responses/responses.js", "resources/responses/responses.mjs"].map((filePath) => ({ | ||
| channelName: "responses", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Responses", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI embeddings API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/embeddings.js", "resources/embeddings.mjs"].map((filePath) => ({ | ||
| channelName: "embeddings", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Embeddings", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI conversations API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/conversations/conversations.js", "resources/conversations/conversations.mjs"].map((filePath) => ({ | ||
| channelName: "conversations", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Conversations", methodName: "create", kind: "Auto" } | ||
| })) | ||
| ]; | ||
| const openaiChannels = { | ||
| OPENAI_CHAT: "orchestrion:openai:chat", | ||
| OPENAI_RESPONSES: "orchestrion:openai:responses", | ||
| OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings", | ||
| OPENAI_CONVERSATIONS: "orchestrion:openai:conversations" | ||
| }; | ||
| exports.openaiChannels = openaiChannels; | ||
| exports.openaiConfig = openaiConfig; | ||
| //# sourceMappingURL=openai.js.map |
| {"version":3,"file":"openai.js","sources":["../../../../src/orchestrion/config/openai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const openaiConfig = [\n // OpenAI chat completions. `Completions.create` returns a thenable `APIPromise` with no callback arg,\n // so `kind: 'Auto'` resolves to `wrapPromise`. openai ships dual CJS/ESM and the matcher compares\n // `filePath` exactly, hence one entry per built file (`.js` for `require`, `.mjs` for `import`).\n ...['resources/chat/completions/completions.js', 'resources/chat/completions/completions.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Completions', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI responses API — same `create(body, options)` shape as chat completions.\n ...['resources/responses/responses.js', 'resources/responses/responses.mjs'].map(filePath => ({\n channelName: 'responses',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Responses', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI embeddings API — same `create(body, options)` shape as chat completions.\n ...['resources/embeddings.js', 'resources/embeddings.mjs'].map(filePath => ({\n channelName: 'embeddings',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Embeddings', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI conversations API — same `create(body, options)` shape as chat completions.\n ...['resources/conversations/conversations.js', 'resources/conversations/conversations.mjs'].map(filePath => ({\n channelName: 'conversations',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Conversations', methodName: 'create', kind: 'Auto' as const },\n })),\n] satisfies InstrumentationConfig[];\n\nexport const openaiChannels = {\n OPENAI_CHAT: 'orchestrion:openai:chat',\n OPENAI_RESPONSES: 'orchestrion:openai:responses',\n OPENAI_EMBEDDINGS: 'orchestrion:openai:embeddings',\n OPENAI_CONVERSATIONS: 'orchestrion:openai:conversations',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,YAAA,GAAe;AAAA;AAAA;AAAA;AAAA,EAI1B,GAAG,CAAC,2CAAA,EAA6C,4CAA4C,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC9G,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,eAAe,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACzF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,kCAAA,EAAoC,mCAAmC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5F,WAAA,EAAa,WAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,aAAa,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACvF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,yBAAA,EAA2B,0BAA0B,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC1E,WAAA,EAAa,YAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,cAAc,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACxF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,0CAAA,EAA4C,2CAA2C,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5G,WAAA,EAAa,eAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,iBAAiB,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GAC3F,CAAE;AACJ;AAEO,MAAM,cAAA,GAAiB;AAAA,EAC5B,WAAA,EAAa,yBAAA;AAAA,EACb,gBAAA,EAAkB,8BAAA;AAAA,EAClB,iBAAA,EAAmB,+BAAA;AAAA,EACnB,oBAAA,EAAsB;AACxB;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const pgConfig = [ | ||
| // `pg` (node-postgres). | ||
| // instruments `Client.prototype.query`/`connect` (both the JS and native | ||
| // clients) plus `pg-pool`'s `Pool.prototype.connect`. | ||
| // `Auto` covers the callback, promise, and streamable-`Submittable` | ||
| // call shapes (like mysql). | ||
| // `pg/lib/client.js` is `class Client { query() {...} connect() {...} }`, | ||
| // so `className`+`methodName` matches directly. | ||
| { | ||
| channelName: "query", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/client.js" }, | ||
| functionQuery: { className: "Client", methodName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/client.js" }, | ||
| functionQuery: { className: "Client", methodName: "connect", kind: "Auto" } | ||
| }, | ||
| // The native client (`pg/lib/native/client.js`) is a constructor function, | ||
| // not a class. | ||
| // `Client.prototype.query = function (config, values, callback) {...}` | ||
| // so it needs `expressionName` (the mysql shape), publishing to the SAME | ||
| // `orchestrion:pg:query`/`:connect` channels as the JS client. | ||
| { | ||
| channelName: "query", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/native/client.js" }, | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/native/client.js" }, | ||
| functionQuery: { expressionName: "connect", kind: "Auto" } | ||
| }, | ||
| // `pg-pool` is `class Pool extends EventEmitter { connect(cb) {...} }`. | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg-pool", versionRange: ">=2.0.0 <4", filePath: "index.js" }, | ||
| functionQuery: { className: "Pool", methodName: "connect", kind: "Auto" } | ||
| } | ||
| ]; | ||
| const pgChannels = { | ||
| PG_QUERY: "orchestrion:pg:query", | ||
| PG_CONNECT: "orchestrion:pg:connect", | ||
| PGPOOL_CONNECT: "orchestrion:pg-pool:connect" | ||
| }; | ||
| exports.pgChannels = pgChannels; | ||
| exports.pgConfig = pgConfig; | ||
| //# sourceMappingURL=pg.js.map |
| {"version":3,"file":"pg.js","sources":["../../../../src/orchestrion/config/pg.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const pgConfig = [\n // `pg` (node-postgres).\n // instruments `Client.prototype.query`/`connect` (both the JS and native\n // clients) plus `pg-pool`'s `Pool.prototype.connect`.\n // `Auto` covers the callback, promise, and streamable-`Submittable`\n // call shapes (like mysql).\n // `pg/lib/client.js` is `class Client { query() {...} connect() {...} }`,\n // so `className`+`methodName` matches directly.\n {\n channelName: 'query',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/client.js' },\n functionQuery: { className: 'Client', methodName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'connect',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/client.js' },\n functionQuery: { className: 'Client', methodName: 'connect', kind: 'Auto' },\n },\n // The native client (`pg/lib/native/client.js`) is a constructor function,\n // not a class.\n // `Client.prototype.query = function (config, values, callback) {...}`\n // so it needs `expressionName` (the mysql shape), publishing to the SAME\n // `orchestrion:pg:query`/`:connect` channels as the JS client.\n {\n channelName: 'query',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/native/client.js' },\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'connect',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/native/client.js' },\n functionQuery: { expressionName: 'connect', kind: 'Auto' },\n },\n // `pg-pool` is `class Pool extends EventEmitter { connect(cb) {...} }`.\n {\n channelName: 'connect',\n module: { name: 'pg-pool', versionRange: '>=2.0.0 <4', filePath: 'index.js' },\n functionQuery: { className: 'Pool', methodName: 'connect', kind: 'Auto' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const pgChannels = {\n PG_QUERY: 'orchestrion:pg:query',\n PG_CONNECT: 'orchestrion:pg:connect',\n PGPOOL_CONNECT: 'orchestrion:pg-pool:connect',\n} as const;\n"],"names":[],"mappings":";;AAEO,MAAM,QAAA,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,eAAA,EAAgB;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,OAAA,EAAS,MAAM,MAAA;AAAO,GAC1E;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,eAAA,EAAgB;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,SAAA,EAAW,MAAM,MAAA;AAAO,GAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,sBAAA,EAAuB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO,GACzD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,sBAAA,EAAuB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,SAAA,EAAW,MAAM,MAAA;AAAO,GAC3D;AAAA;AAAA,EAEA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,YAAA,EAAc,UAAU,UAAA,EAAW;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,QAAQ,UAAA,EAAY,SAAA,EAAW,MAAM,MAAA;AAAO;AAE5E;AAEO,MAAM,UAAA,GAAa;AAAA,EACxB,QAAA,EAAU,sBAAA;AAAA,EACV,UAAA,EAAY,wBAAA;AAAA,EACZ,cAAA,EAAgB;AAClB;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const vercelAiConfig = [ | ||
| // Vercel AI v6: mirror the v7 native `ai:telemetry` channel by injecting | ||
| // channels into the top-level entry points. `resolveLanguageModel` is wrapped | ||
| // not to span it, but so the subscriber can monkey-patch `doGenerate`/ | ||
| // `doStream` on the returned model (the only way to span the model call, | ||
| // which is an inline call with no injectable definition in `ai`). | ||
| // `streamText` returns its result synchronously (streaming is lazy), so it's | ||
| // `Sync`; the subscriber binds the span via `bindTracingChannelToSpan`, which | ||
| // ends it when the (synchronous) call returns. | ||
| ...vercelAiV6Entries("generateText", "generateText", "Async"), | ||
| ...vercelAiV6Entries("streamText", "streamText", "Sync"), | ||
| ...vercelAiV6Entries("embed", "embed", "Async"), | ||
| ...vercelAiV6Entries("embedMany", "embedMany", "Async"), | ||
| ...vercelAiV6Entries("executeToolCall", "executeToolCall", "Async"), | ||
| ...vercelAiV6Entries("resolveLanguageModel", "resolveLanguageModel", "Sync") | ||
| ]; | ||
| const vercelAiChannels = { | ||
| // Vercel AI (`ai`) v6: orchestrion injects these so the same channel-based | ||
| // integration that consumes `ai`'s native `ai:telemetry` channel (v7) can | ||
| // also instrument v6. Each maps to a top-level function in `ai`'s bundle. | ||
| VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText", | ||
| VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText", | ||
| VERCEL_AI_EMBED: "orchestrion:ai:embed", | ||
| VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany", | ||
| VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall", | ||
| // `resolveLanguageModel` is the single chokepoint every model call flows | ||
| // through; we wrap it to monkey-patch `doGenerate`/`doStream` on the returned | ||
| // model (the model-call site itself is an inline call with no injectable | ||
| // definition). | ||
| VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel" | ||
| }; | ||
| function vercelAiV6Entries(channelName, functionName, kind) { | ||
| return ["dist/index.js", "dist/index.mjs"].map((filePath) => ({ | ||
| channelName, | ||
| module: { name: "ai", versionRange: ">=6.0.0 <7.0.0", filePath }, | ||
| functionQuery: { functionName, kind } | ||
| })); | ||
| } | ||
| exports.vercelAiChannels = vercelAiChannels; | ||
| exports.vercelAiConfig = vercelAiConfig; | ||
| //# sourceMappingURL=vercel-ai.js.map |
| {"version":3,"file":"vercel-ai.js","sources":["../../../../src/orchestrion/config/vercel-ai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const vercelAiConfig = [\n // Vercel AI v6: mirror the v7 native `ai:telemetry` channel by injecting\n // channels into the top-level entry points. `resolveLanguageModel` is wrapped\n // not to span it, but so the subscriber can monkey-patch `doGenerate`/\n // `doStream` on the returned model (the only way to span the model call,\n // which is an inline call with no injectable definition in `ai`).\n // `streamText` returns its result synchronously (streaming is lazy), so it's\n // `Sync`; the subscriber binds the span via `bindTracingChannelToSpan`, which\n // ends it when the (synchronous) call returns.\n ...vercelAiV6Entries('generateText', 'generateText', 'Async'),\n ...vercelAiV6Entries('streamText', 'streamText', 'Sync'),\n ...vercelAiV6Entries('embed', 'embed', 'Async'),\n ...vercelAiV6Entries('embedMany', 'embedMany', 'Async'),\n ...vercelAiV6Entries('executeToolCall', 'executeToolCall', 'Async'),\n ...vercelAiV6Entries('resolveLanguageModel', 'resolveLanguageModel', 'Sync'),\n] satisfies InstrumentationConfig[];\n\nexport const vercelAiChannels = {\n // Vercel AI (`ai`) v6: orchestrion injects these so the same channel-based\n // integration that consumes `ai`'s native `ai:telemetry` channel (v7) can\n // also instrument v6. Each maps to a top-level function in `ai`'s bundle.\n VERCEL_AI_GENERATE_TEXT: 'orchestrion:ai:generateText',\n VERCEL_AI_STREAM_TEXT: 'orchestrion:ai:streamText',\n VERCEL_AI_EMBED: 'orchestrion:ai:embed',\n VERCEL_AI_EMBED_MANY: 'orchestrion:ai:embedMany',\n VERCEL_AI_EXECUTE_TOOL_CALL: 'orchestrion:ai:executeToolCall',\n // `resolveLanguageModel` is the single chokepoint every model call flows\n // through; we wrap it to monkey-patch `doGenerate`/`doStream` on the returned\n // model (the model-call site itself is an inline call with no injectable\n // definition).\n VERCEL_AI_RESOLVE_LANGUAGE_MODEL: 'orchestrion:ai:resolveLanguageModel',\n} as const;\n\n/**\n * The central list of channel injections orchestrion should perform.\n *\n * This module has NO side effects — it's the only thing both the runtime hook\n * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …)\n * import from. Adding a new instrumented method is one entry here plus one\n * subscriber in `integrations/<lib>/tracing-channel.ts`.\n *\n * `channelName` here is the unprefixed suffix; the actual diagnostics_channel\n * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`).\n */\n/**\n * `ai` ships a single bundled entry per module system, so each instrumented\n * function needs one config entry per file (the app loads whichever matches its\n * module system). This expands a single target into both.\n */\nfunction vercelAiV6Entries(channelName: string, functionName: string, kind: 'Async' | 'Sync'): InstrumentationConfig[] {\n return ['dist/index.js', 'dist/index.mjs'].map(filePath => ({\n channelName,\n module: { name: 'ai', versionRange: '>=6.0.0 <7.0.0', filePath },\n functionQuery: { functionName, kind },\n }));\n}\n"],"names":[],"mappings":";;AAEO,MAAM,cAAA,GAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS5B,GAAG,iBAAA,CAAkB,cAAA,EAAgB,cAAA,EAAgB,OAAO,CAAA;AAAA,EAC5D,GAAG,iBAAA,CAAkB,YAAA,EAAc,YAAA,EAAc,MAAM,CAAA;AAAA,EACvD,GAAG,iBAAA,CAAkB,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA;AAAA,EAC9C,GAAG,iBAAA,CAAkB,WAAA,EAAa,WAAA,EAAa,OAAO,CAAA;AAAA,EACtD,GAAG,iBAAA,CAAkB,iBAAA,EAAmB,iBAAA,EAAmB,OAAO,CAAA;AAAA,EAClE,GAAG,iBAAA,CAAkB,sBAAA,EAAwB,sBAAA,EAAwB,MAAM;AAC7E;AAEO,MAAM,gBAAA,GAAmB;AAAA;AAAA;AAAA;AAAA,EAI9B,uBAAA,EAAyB,6BAAA;AAAA,EACzB,qBAAA,EAAuB,2BAAA;AAAA,EACvB,eAAA,EAAiB,sBAAA;AAAA,EACjB,oBAAA,EAAsB,0BAAA;AAAA,EACtB,2BAAA,EAA6B,gCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7B,gCAAA,EAAkC;AACpC;AAkBA,SAAS,iBAAA,CAAkB,WAAA,EAAqB,YAAA,EAAsB,IAAA,EAAiD;AACrH,EAAA,OAAO,CAAC,eAAA,EAAiB,gBAAgB,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC1D,WAAA;AAAA,IACA,QAAQ,EAAE,IAAA,EAAM,IAAA,EAAM,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,IAC/D,aAAA,EAAe,EAAE,YAAA,EAAc,IAAA;AAAK,GACtC,CAAE,CAAA;AACJ;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const serializationSubsets = [ | ||
| { | ||
| regex: /^ECHO/i, | ||
| args: 0 | ||
| }, | ||
| { | ||
| regex: /^(LPUSH|MSET|PFA|PUBLISH|RPUSH|SADD|SET|SPUBLISH|XADD|ZADD)/i, | ||
| args: 1 | ||
| }, | ||
| { | ||
| regex: /^(HSET|HMSET|LSET|LINSERT)/i, | ||
| args: 2 | ||
| }, | ||
| { | ||
| regex: /^(ACL|BIT|B[LRZ]|CLIENT|CLUSTER|CONFIG|COMMAND|DECR|DEL|EVAL|EX|FUNCTION|GEO|GET|HINCR|HMGET|HSCAN|INCR|L[TRLM]|MEMORY|P[EFISTU]|RPOP|S[CDIMORSU]|XACK|X[CDGILPRT]|Z[CDILMPRS])/i, | ||
| args: -1 | ||
| } | ||
| ]; | ||
| const defaultDbStatementSerializer = (cmdName, cmdArgs) => { | ||
| if (Array.isArray(cmdArgs) && cmdArgs.length) { | ||
| const nArgsToSerialize = serializationSubsets.find(({ regex }) => regex.test(cmdName))?.args ?? 0; | ||
| const argsToSerialize = nArgsToSerialize >= 0 ? cmdArgs.slice(0, nArgsToSerialize) : cmdArgs.slice(); | ||
| if (cmdArgs.length > argsToSerialize.length) { | ||
| argsToSerialize.push(`[${cmdArgs.length - nArgsToSerialize} other arguments]`); | ||
| } | ||
| return `${cmdName} ${argsToSerialize.join(" ")}`; | ||
| } | ||
| return cmdName; | ||
| }; | ||
| exports.defaultDbStatementSerializer = defaultDbStatementSerializer; | ||
| //# sourceMappingURL=redis-statement-serializer.js.map |
| {"version":3,"file":"redis-statement-serializer.js","sources":["../../../src/redis/redis-statement-serializer.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-redis-v0.62.0/packages/redis-common\n * - Upstream version: @opentelemetry/redis-common@0.38.2\n *\n * Single canonical copy, shared by the orchestrion ioredis subscriber here and\n * the node SDK's vendored redis/ioredis instrumentations (which re-export it via\n * `packages/node/src/integrations/tracing/redis/vendored/redis-common.ts`).\n */\n/* eslint-disable -- vendored @opentelemetry/redis-common */\n\n/**\n * List of regexes and the number of arguments that should be serialized for matching commands.\n * For example, HSET should serialize which key and field it's operating on, but not its value.\n * Setting the subset to -1 will serialize all arguments.\n * Commands without a match will have their first argument serialized.\n *\n * Refer to https://redis.io/commands/ for the full list.\n */\nconst serializationSubsets = [\n {\n regex: /^ECHO/i,\n args: 0,\n },\n {\n regex: /^(LPUSH|MSET|PFA|PUBLISH|RPUSH|SADD|SET|SPUBLISH|XADD|ZADD)/i,\n args: 1,\n },\n {\n regex: /^(HSET|HMSET|LSET|LINSERT)/i,\n args: 2,\n },\n {\n regex:\n /^(ACL|BIT|B[LRZ]|CLIENT|CLUSTER|CONFIG|COMMAND|DECR|DEL|EVAL|EX|FUNCTION|GEO|GET|HINCR|HMGET|HSCAN|INCR|L[TRLM]|MEMORY|P[EFISTU]|RPOP|S[CDIMORSU]|XACK|X[CDGILPRT]|Z[CDILMPRS])/i,\n args: -1,\n },\n];\n\n/**\n * Given the redis command name and arguments, return a combination of the\n * command name + the allowed arguments according to `serializationSubsets`.\n */\nexport const defaultDbStatementSerializer = (\n cmdName: string,\n cmdArgs: Array<string | Buffer | number | unknown[]>,\n): string => {\n if (Array.isArray(cmdArgs) && cmdArgs.length) {\n const nArgsToSerialize = serializationSubsets.find(({ regex }) => regex.test(cmdName))?.args ?? 0;\n const argsToSerialize: Array<string | Buffer | number | unknown[]> =\n nArgsToSerialize >= 0 ? cmdArgs.slice(0, nArgsToSerialize) : cmdArgs.slice();\n if (cmdArgs.length > argsToSerialize.length) {\n argsToSerialize.push(`[${cmdArgs.length - nArgsToSerialize} other arguments]`);\n }\n return `${cmdName} ${argsToSerialize.join(' ')}`;\n }\n return cmdName;\n};\n"],"names":[],"mappings":";;AAsBA,MAAM,oBAAA,GAAuB;AAAA,EAC3B;AAAA,IACE,KAAA,EAAO,QAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,8DAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,6BAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EACE,kLAAA;AAAA,IACF,IAAA,EAAM;AAAA;AAEV,CAAA;AAMO,MAAM,4BAAA,GAA+B,CAC1C,OAAA,EACA,OAAA,KACW;AACX,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,QAAQ,MAAA,EAAQ;AAC5C,IAAA,MAAM,gBAAA,GAAmB,oBAAA,CAAqB,IAAA,CAAK,CAAC,EAAE,KAAA,EAAM,KAAM,KAAA,CAAM,IAAA,CAAK,OAAO,CAAC,CAAA,EAAG,IAAA,IAAQ,CAAA;AAChG,IAAA,MAAM,eAAA,GACJ,oBAAoB,CAAA,GAAI,OAAA,CAAQ,MAAM,CAAA,EAAG,gBAAgB,CAAA,GAAI,OAAA,CAAQ,KAAA,EAAM;AAC7E,IAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,eAAA,CAAgB,MAAA,EAAQ;AAC3C,MAAA,eAAA,CAAgB,IAAA,CAAK,CAAA,CAAA,EAAI,OAAA,CAAQ,MAAA,GAAS,gBAAgB,CAAA,iBAAA,CAAmB,CAAA;AAAA,IAC/E;AACA,IAAA,OAAO,GAAG,OAAO,CAAA,CAAA,EAAI,eAAA,CAAgB,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,OAAA;AACT;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const core = require('@sentry/core'); | ||
| const debugBuild = require('../debug-build.js'); | ||
| const channels = require('../orchestrion/channels.js'); | ||
| const tracingChannel = require('../tracing-channel.js'); | ||
| const vercelAiDcSubscriber = require('./vercel-ai-dc-subscriber.js'); | ||
| const PATCHED = /* @__PURE__ */ Symbol("SentryVercelAiModelPatched"); | ||
| let callIdCounter = 0; | ||
| function nextCallId() { | ||
| return `v6-${++callIdCounter}`; | ||
| } | ||
| const messages = /* @__PURE__ */ new WeakMap(); | ||
| const operationSpans = /* @__PURE__ */ new WeakSet(); | ||
| const callIdBySpan = /* @__PURE__ */ new WeakMap(); | ||
| const recordingBySpan = /* @__PURE__ */ new WeakMap(); | ||
| const suppressedTelemetry = /* @__PURE__ */ new WeakSet(); | ||
| let subscribed = false; | ||
| function subscribeVercelAiOrchestrionChannels(tracingChannel, options = {}) { | ||
| if (subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| try { | ||
| bindOperation(tracingChannel, channels.CHANNELS.VERCEL_AI_GENERATE_TEXT, buildTextMessage("generateText"), options); | ||
| bindOperation(tracingChannel, channels.CHANNELS.VERCEL_AI_STREAM_TEXT, buildTextMessage("streamText"), options); | ||
| bindOperation( | ||
| tracingChannel, | ||
| channels.CHANNELS.VERCEL_AI_EMBED, | ||
| (callOptions, telemetry) => ({ | ||
| type: "embed", | ||
| event: { | ||
| callId: nextCallId(), | ||
| ...modelFields(callOptions.model), | ||
| maxRetries: callOptions.maxRetries, | ||
| value: callOptions.value, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| bindOperation( | ||
| tracingChannel, | ||
| channels.CHANNELS.VERCEL_AI_EMBED_MANY, | ||
| // `embedMany` takes a `values` array (vs `embed`'s single `value`); the shared core reads it as the | ||
| // embeddings input, matching the OTel path's batch `ai.embedMany` span. | ||
| (callOptions, telemetry) => ({ | ||
| type: "embedMany", | ||
| event: { | ||
| callId: nextCallId(), | ||
| ...modelFields(callOptions.model), | ||
| maxRetries: callOptions.maxRetries, | ||
| values: callOptions.values, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| bindOperation( | ||
| tracingChannel, | ||
| channels.CHANNELS.VERCEL_AI_EXECUTE_TOOL_CALL, | ||
| (callOptions, telemetry) => ({ | ||
| type: "executeTool", | ||
| // v6 carries the tool definitions on the executeToolCall args (a record keyed by name); | ||
| // the shared core reads the matching tool's `description` for the span. | ||
| event: { | ||
| callId: nextCallId(), | ||
| toolCall: callOptions.toolCall, | ||
| tools: callOptions.tools, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| subscribeResolveLanguageModel(tracingChannel, channels.CHANNELS.VERCEL_AI_RESOLVE_LANGUAGE_MODEL, options); | ||
| } catch { | ||
| debugBuild.DEBUG_BUILD && core.debug.log("Vercel AI orchestrion channel subscription failed."); | ||
| } | ||
| } | ||
| function bindOperation(tracingChannel$1, channelName, build, options) { | ||
| const channel = tracingChannel$1(channelName); | ||
| const buildOperationSpan = (data) => { | ||
| const callOptions = isRecord(data.arguments[0]) ? data.arguments[0] : {}; | ||
| const telemetry = isRecord(callOptions.experimental_telemetry) ? callOptions.experimental_telemetry : {}; | ||
| if (telemetry.isEnabled === false && !suppressedTelemetry.has(telemetry)) { | ||
| return void 0; | ||
| } | ||
| const message = build(callOptions, telemetry); | ||
| suppressNativeTelemetry(callOptions, telemetry); | ||
| const span = vercelAiDcSubscriber.createSpanFromMessage(message, options); | ||
| if (span) { | ||
| messages.set(data, message); | ||
| operationSpans.add(span); | ||
| const callId = asString(message.event.callId); | ||
| if (callId) { | ||
| callIdBySpan.set(span, callId); | ||
| } | ||
| recordingBySpan.set(span, recording(telemetry)); | ||
| } | ||
| return span; | ||
| }; | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| channel, | ||
| (data) => buildOperationSpan(data), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| const message = messages.get(data); | ||
| if (!message) { | ||
| return; | ||
| } | ||
| if (!("error" in data)) { | ||
| message.result = message.type === "executeTool" ? { output: data.result } : data.result; | ||
| vercelAiDcSubscriber.enrichSpanOnEnd(span, message, options); | ||
| } | ||
| if (message.type !== "streamText") { | ||
| vercelAiDcSubscriber.clearOperationId(message); | ||
| } | ||
| messages.delete(data); | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| function suppressNativeTelemetry(callOptions, telemetry) { | ||
| if (telemetry.isEnabled !== true) { | ||
| return; | ||
| } | ||
| const suppressed = { ...telemetry, isEnabled: false }; | ||
| suppressedTelemetry.add(suppressed); | ||
| callOptions.experimental_telemetry = suppressed; | ||
| } | ||
| function subscribeResolveLanguageModel(tracingChannel, channelName, options) { | ||
| tracingChannel(channelName).subscribe({ | ||
| end(rawCtx) { | ||
| const ctx = rawCtx; | ||
| if (!isRecord(ctx.result)) { | ||
| return; | ||
| } | ||
| const model = ctx.result; | ||
| if (!model[PATCHED]) { | ||
| model[PATCHED] = true; | ||
| patchModelMethod(model, "doGenerate", options); | ||
| patchModelMethod(model, "doStream", options); | ||
| } | ||
| }, | ||
| start() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| } | ||
| function resolveModelCallParent() { | ||
| const active = core.getActiveSpan(); | ||
| return active && operationSpans.has(active) ? active : void 0; | ||
| } | ||
| function patchModelMethod(model, method, options) { | ||
| const original = model[method]; | ||
| if (typeof original !== "function") { | ||
| return; | ||
| } | ||
| model[method] = function(...args) { | ||
| const parent = resolveModelCallParent(); | ||
| if (!parent) { | ||
| return Promise.resolve(original.apply(this, args)); | ||
| } | ||
| const callArgs = isRecord(args[0]) ? args[0] : {}; | ||
| const callId = callIdBySpan.get(parent); | ||
| const message = { | ||
| type: "languageModelCall", | ||
| event: { | ||
| callId, | ||
| provider: model.provider, | ||
| modelId: model.modelId, | ||
| tools: callArgs.tools, | ||
| messages: callArgs.prompt, | ||
| // Inherit the enclosing operation's per-call recording flags so inputs/tools/outputs are recorded on | ||
| // the model-call span whenever they are on the parent `invoke_agent` span. | ||
| ...recordingBySpan.get(parent) | ||
| } | ||
| }; | ||
| const span = core.withActiveSpan(parent, () => vercelAiDcSubscriber.createSpanFromMessage(message, options)); | ||
| if (!span) { | ||
| return Promise.resolve(original.apply(this, args)); | ||
| } | ||
| const clearStreamCallId = () => { | ||
| if (method === "doStream" && callId) { | ||
| vercelAiDcSubscriber.clearOperationCallId(callId); | ||
| } | ||
| }; | ||
| const failSpan = (error) => { | ||
| span.setStatus({ code: core.SPAN_STATUS_ERROR, message: error instanceof Error ? error.message : "unknown_error" }); | ||
| span.end(); | ||
| clearStreamCallId(); | ||
| throw error; | ||
| }; | ||
| try { | ||
| const result = Promise.resolve(original.apply(this, args)); | ||
| return result.then((value) => { | ||
| message.result = value; | ||
| vercelAiDcSubscriber.enrichSpanOnEnd(span, message, options); | ||
| span.end(); | ||
| clearStreamCallId(); | ||
| return value; | ||
| }, failSpan); | ||
| } catch (error) { | ||
| return failSpan(error); | ||
| } | ||
| }; | ||
| } | ||
| function buildTextMessage(type) { | ||
| return (options, telemetry) => ({ | ||
| type, | ||
| event: { | ||
| callId: nextCallId(), | ||
| operationId: `ai.${type}`, | ||
| functionId: asString(telemetry.functionId), | ||
| ...modelFields(options.model), | ||
| maxRetries: options.maxRetries, | ||
| // Normalize to the message-array shape the shared core (and v7's channel) expects: a bare string | ||
| // `prompt` becomes a single user message, matching the SDK's own normalization. | ||
| messages: normalizePromptMessages(options), | ||
| ...recording(telemetry) | ||
| } | ||
| }); | ||
| } | ||
| function normalizePromptMessages(options) { | ||
| if (Array.isArray(options.messages)) { | ||
| return options.messages; | ||
| } | ||
| if (typeof options.prompt === "string") { | ||
| return [{ role: "user", content: options.prompt }]; | ||
| } | ||
| return options.messages ?? options.prompt; | ||
| } | ||
| function recording(telemetry) { | ||
| return { recordInputs: telemetry.recordInputs, recordOutputs: telemetry.recordOutputs }; | ||
| } | ||
| function modelFields(model) { | ||
| return { provider: modelField(model, "provider"), modelId: modelField(model, "modelId") }; | ||
| } | ||
| function modelField(model, field) { | ||
| return isRecord(model) ? asString(model[field]) : void 0; | ||
| } | ||
| function asString(value) { | ||
| return typeof value === "string" ? value : void 0; | ||
| } | ||
| function isRecord(value) { | ||
| return typeof value === "object" && value !== null; | ||
| } | ||
| exports.subscribeVercelAiOrchestrionChannels = subscribeVercelAiOrchestrionChannels; | ||
| //# sourceMappingURL=vercel-ai-orchestrion-v6-subscriber.js.map |
| {"version":3,"file":"vercel-ai-orchestrion-v6-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-orchestrion-v6-subscriber.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { debug, getActiveSpan, SPAN_STATUS_ERROR, withActiveSpan } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { CHANNELS } from '../orchestrion/channels';\nimport { bindTracingChannelToSpan, type TracingChannelPayloadWithSpan } from '../tracing-channel';\nimport {\n clearOperationCallId,\n clearOperationId,\n createSpanFromMessage,\n enrichSpanOnEnd,\n type VercelAiChannelMessage,\n type VercelAiChannelOptions,\n type VercelAiTracingChannelFactory,\n} from './vercel-ai-dc-subscriber';\n\n/**\n * v6 channel adapter for the Vercel AI (`ai`) SDK.\n *\n * `ai` >= 7 publishes a normalized `ai:telemetry` tracing channel natively\n * (consumed by `subscribeVercelAiTracingChannel`). v6 has no such channel, so\n * orchestrion injects `orchestrion:ai:*` channels around the top-level\n * functions (see `orchestrion/config/index.ts`). The injected channels carry only the\n * wrapped call's `{ arguments, result, error }` — NOT v7's normalized `event`\n * object — so this adapter reconstructs an equivalent {@link VercelAiChannelMessage}\n * from v6's argument/result shapes and delegates to the SAME span-building core\n * (`createSpanFromMessage` / `enrichSpanOnEnd`) the v7 subscriber uses, so the\n * emitted spans are identical between v6 and v7.\n *\n * The model call (`languageModelCall` / `generate_content` span) has no\n * injectable definition in `ai`, so we instead wrap `resolveLanguageModel` (the\n * single chokepoint every model call flows through) and monkey-patch\n * `doGenerate`/`doStream` on the returned model.\n */\n\n/** Shape orchestrion's transform attaches to the tracing-channel context. */\ninterface OrchestrionContext {\n arguments: unknown[];\n result?: unknown;\n error?: unknown;\n}\n\n/** Builds the normalized message for a channel from the wrapped call's first-arg options. */\ntype MessageBuilder = (options: Record<string, unknown>, telemetry: Record<string, unknown>) => VercelAiChannelMessage;\n\n/** A resolved `ai` language model — has `doGenerate`/`doStream` and identity fields. */\ninterface ResolvedModel {\n modelId?: string;\n provider?: string;\n doGenerate?: (...args: unknown[]) => Promise<unknown>;\n doStream?: (...args: unknown[]) => Promise<unknown>;\n}\n\nconst PATCHED = Symbol('SentryVercelAiModelPatched');\n\n/** A resolved model with our patch bookkeeping (idempotency flag). */\ntype PatchableModel = ResolvedModel & { [PATCHED]?: boolean };\n\n// Per-operation correlation id. No Date/random (unavailable / non-deterministic) — a counter is enough.\nlet callIdCounter = 0;\nfunction nextCallId(): string {\n return `v6-${++callIdCounter}`;\n}\n\n// The message built on `start` for each operation, keyed by the (stable-identity) channel context, so\n// the `beforeSpanEnd` handler can enrich the span from the settled result and clear the `callId` maps.\nconst messages = new WeakMap<object, VercelAiChannelMessage>();\n// The spans we opened for top-level operations, and each one's `callId`. A model call resolves its\n// parent against this set (so it never mis-attributes to the enclosing `main`/user span) and reads the\n// parent's `callId` so its span can be named after the operation (e.g. `ai.streamText.doStream`).\nconst operationSpans = new WeakSet<Span>();\nconst callIdBySpan = new WeakMap<Span, string>();\n// The operation's per-call recording flags (`experimental_telemetry.recordInputs/recordOutputs`), keyed by\n// its span. A model call carries no telemetry of its own, so it inherits the enclosing operation's flags —\n// otherwise a per-call `recordInputs: true` would record inputs on the `invoke_agent` span but not on the\n// child `generate_content` span (whose event would fall back to the global default). v7's channel forwards\n// these flags on every event, so this keeps v6 identical.\nconst recordingBySpan = new WeakMap<Span, ReturnType<typeof recording>>();\n\n// The `experimental_telemetry` objects we swapped in to suppress `ai`'s native OTel spans (see\n// `suppressNativeTelemetry`). Our skip logic treats `isEnabled === false` as \"user disabled telemetry,\n// emit no span\"; without this set, a call whose options object we already neutralized — or a user-shared\n// telemetry object we replaced on a prior call — would be misread as user-disabled and lose its span.\nconst suppressedTelemetry = new WeakSet<object>();\n\nlet subscribed = false;\n\n/**\n * Subscribe the v6 orchestrion channel adapter. Safe to always call: inert on\n * `ai` >= 7 (those channels are never published) and when orchestrion injection\n * isn't active. Idempotent.\n *\n * `tracingChannel` is the platform-provided factory (the same one passed to\n * `subscribeVercelAiTracingChannel`); `options` pins the recording settings at\n * subscribe time so we never look the integration up per event.\n */\nexport function subscribeVercelAiOrchestrionChannels(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n try {\n bindOperation(tracingChannel, CHANNELS.VERCEL_AI_GENERATE_TEXT, buildTextMessage('generateText'), options);\n bindOperation(tracingChannel, CHANNELS.VERCEL_AI_STREAM_TEXT, buildTextMessage('streamText'), options);\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EMBED,\n (callOptions, telemetry) => ({\n type: 'embed',\n event: {\n callId: nextCallId(),\n ...modelFields(callOptions.model),\n maxRetries: callOptions.maxRetries,\n value: callOptions.value,\n ...recording(telemetry),\n },\n }),\n options,\n );\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EMBED_MANY,\n // `embedMany` takes a `values` array (vs `embed`'s single `value`); the shared core reads it as the\n // embeddings input, matching the OTel path's batch `ai.embedMany` span.\n (callOptions, telemetry) => ({\n type: 'embedMany',\n event: {\n callId: nextCallId(),\n ...modelFields(callOptions.model),\n maxRetries: callOptions.maxRetries,\n values: callOptions.values,\n ...recording(telemetry),\n },\n }),\n options,\n );\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EXECUTE_TOOL_CALL,\n (callOptions, telemetry) => ({\n type: 'executeTool',\n // v6 carries the tool definitions on the executeToolCall args (a record keyed by name);\n // the shared core reads the matching tool's `description` for the span.\n event: {\n callId: nextCallId(),\n toolCall: callOptions.toolCall,\n tools: callOptions.tools,\n ...recording(telemetry),\n },\n }),\n options,\n );\n subscribeResolveLanguageModel(tracingChannel, CHANNELS.VERCEL_AI_RESOLVE_LANGUAGE_MODEL, options);\n } catch {\n DEBUG_BUILD && debug.log('Vercel AI orchestrion channel subscription failed.');\n }\n}\n\n/**\n * Bind one operation channel: `getSpan` opens a span from the message reconstructed out of the wrapped\n * call's first argument; `beforeSpanEnd` enriches it from the settled result (tokens, output messages,\n * finish reasons, …) before the helper ends the span.\n *\n * An operation whose `experimental_telemetry.isEnabled` is explicitly `false` is skipped entirely (no\n * span): the orchestrion channel fires regardless of that flag, whereas v7's native `ai:telemetry`\n * channel is simply not published in that case — so we reproduce v7's \"no telemetry → no span\".\n */\nfunction bindOperation(\n tracingChannel: VercelAiTracingChannelFactory,\n channelName: string,\n build: MessageBuilder,\n options: VercelAiChannelOptions,\n): void {\n const channel = tracingChannel<OrchestrionContext>(channelName);\n\n // Build the operation span from the wrapped call's first argument and track it (so a model call can\n // resolve it as its parent). `bindTracingChannelToSpan` calls this once at channel `start` and makes\n // the returned span the active async context for the operation's duration — that active span is what\n // `resolveModelCallParent` reads. It also sets `data._sentrySpan`, so we don't here.\n const buildOperationSpan = (data: TracingChannelPayloadWithSpan<OrchestrionContext>): Span | undefined => {\n const callOptions = isRecord(data.arguments[0]) ? data.arguments[0] : {};\n const telemetry = isRecord(callOptions.experimental_telemetry) ? callOptions.experimental_telemetry : {};\n // `isEnabled === false` means the user opted out — emit no span. But `isEnabled` is also `false` on\n // the telemetry object we swap in to suppress native spans, so don't mistake our own object for a\n // user opt-out (which would drop the span on a call whose options we already neutralized).\n if (telemetry.isEnabled === false && !suppressedTelemetry.has(telemetry)) {\n return undefined;\n }\n const message = build(callOptions, telemetry);\n // Stop `ai` from emitting its own native OTel spans for this call — we build the equivalent spans\n // from the channels, so the SDK's would be duplicates. Reads above have already captured everything\n // we need off `telemetry`.\n suppressNativeTelemetry(callOptions, telemetry);\n const span = createSpanFromMessage(message, options);\n if (span) {\n messages.set(data, message);\n operationSpans.add(span);\n const callId = asString(message.event.callId);\n if (callId) {\n callIdBySpan.set(span, callId);\n }\n recordingBySpan.set(span, recording(telemetry));\n }\n return span;\n };\n\n bindTracingChannelToSpan(\n channel,\n (data: TracingChannelPayloadWithSpan<OrchestrionContext>) => buildOperationSpan(data),\n {\n beforeSpanEnd: (span, data) => {\n const message = messages.get(data);\n if (!message) {\n return;\n }\n // The helper's `error` handler already set the span status; only enrich from a successful result.\n if (!('error' in data)) {\n // v6's `executeToolCall` returns the tool result/error object directly, whereas the shared core\n // (matching v7) expects it nested under `output`; wrap it so tool-error detection works.\n message.result = message.type === 'executeTool' ? { output: data.result } : data.result;\n enrichSpanOnEnd(span, message, options);\n }\n // A `streamText` model call runs after this (synchronously-returning) operation's span has\n // already ended, so its `callId` entry must outlive the operation — it's cleared once the model\n // call settles (see `patchModelMethod`). Every other operation can clear here.\n if (message.type !== 'streamText') {\n clearOperationId(message);\n }\n messages.delete(data);\n },\n },\n );\n}\n\n/**\n * Neutralize `ai`'s native OpenTelemetry instrumentation for this call by pointing\n * `experimental_telemetry` at a copy with `isEnabled: false`. `ai`'s `getTracer` then returns its\n * internal no-op tracer, so it never creates (nor sets active) the duplicate `ai.*` spans we'd\n * otherwise have to drop.\n *\n * Only a call that explicitly enabled telemetry emits native spans — otherwise `ai` already uses its\n * no-op tracer, so there's nothing to suppress and we leave the user's options untouched. When\n * `isEnabled === true`, `telemetry` is `callOptions.experimental_telemetry` and `callOptions` is the\n * real first argument the SDK will read, so the reassignment takes effect for the wrapped call. We\n * replace rather than mutate in place, so a telemetry object the user shares across calls keeps its own\n * `isEnabled: true`; the replacement is tracked in `suppressedTelemetry` so our skip logic doesn't\n * later read it back as a user opt-out.\n */\nfunction suppressNativeTelemetry(callOptions: Record<string, unknown>, telemetry: Record<string, unknown>): void {\n if (telemetry.isEnabled !== true) {\n return;\n }\n const suppressed = { ...telemetry, isEnabled: false };\n suppressedTelemetry.add(suppressed);\n callOptions.experimental_telemetry = suppressed;\n}\n\n/**\n * `resolveLanguageModel` returns the model every call flows through. We don't span it — on `end` we\n * monkey-patch `doGenerate`/`doStream` on the returned model so each invocation produces a\n * `languageModelCall` span parented to the enclosing invoke_agent span.\n */\nfunction subscribeResolveLanguageModel(\n tracingChannel: VercelAiTracingChannelFactory,\n channelName: string,\n options: VercelAiChannelOptions,\n): void {\n tracingChannel<OrchestrionContext>(channelName).subscribe({\n end(rawCtx) {\n const ctx = rawCtx as OrchestrionContext;\n if (!isRecord(ctx.result)) {\n return;\n }\n const model = ctx.result as PatchableModel;\n // Patch the model's `doGenerate`/`doStream` once. The model call recovers its parent from the\n // active async context at call time (the operation span `bindTracingChannelToSpan` bound), which\n // propagates into the model call for `streamText` too, so there is nothing to capture on the model here.\n if (!model[PATCHED]) {\n model[PATCHED] = true;\n patchModelMethod(model, 'doGenerate', options);\n patchModelMethod(model, 'doStream', options);\n }\n },\n start() {\n /* no-op */\n },\n asyncStart() {\n /* no-op */\n },\n asyncEnd() {\n /* no-op */\n },\n error() {\n /* no-op */\n },\n });\n}\n\n/**\n * Pick the invoke_agent span a model call should hang under: the operation span that\n * `bindTracingChannelToSpan` planted as the active async context for the enclosing operation.\n *\n * Because we suppress `ai`'s native telemetry (so it never installs its own span as active), the active\n * span inside `doGenerate`/`doStream` is our operation span. The `operationSpans` gate makes this return\n * `undefined` when the active span isn't one of ours — e.g. telemetry was disabled for the call so we\n * opened no operation span and the active span is the user's enclosing span — so the model call is\n * skipped rather than mis-parented.\n *\n * This covers `generateText`/`embed` (whose model call is awaited inside the operation body) and\n * `streamText` alike — `ai` initiates the stream synchronously within the operation's bound context, so\n * the later `doStream` continuation restores the same active span even though the operation's span has\n * already ended. The per-operation binding also disambiguates concurrent calls that share one model\n * instance (a single mutable slot on the shared model could not — it would hold whichever operation\n * resolved the model last).\n */\nfunction resolveModelCallParent(): Span | undefined {\n const active = getActiveSpan();\n return active && operationSpans.has(active) ? active : undefined;\n}\n\nfunction patchModelMethod(\n model: PatchableModel,\n method: 'doGenerate' | 'doStream',\n options: VercelAiChannelOptions,\n): void {\n const original = model[method];\n if (typeof original !== 'function') {\n return;\n }\n model[method] = function (this: unknown, ...args: unknown[]): Promise<unknown> {\n const parent = resolveModelCallParent();\n // No enclosing operation span (e.g. telemetry disabled for the call) → don't open a model-call span.\n if (!parent) {\n return Promise.resolve(original.apply(this, args));\n }\n\n const callArgs = isRecord(args[0]) ? args[0] : {};\n // Carry the operation's `callId` so the shared core can name the span after it\n // (`ai.generateText.doGenerate` / `ai.streamText.doStream`).\n const callId = callIdBySpan.get(parent);\n const message: VercelAiChannelMessage = {\n type: 'languageModelCall',\n event: {\n callId,\n provider: model.provider,\n modelId: model.modelId,\n tools: callArgs.tools,\n messages: callArgs.prompt,\n // Inherit the enclosing operation's per-call recording flags so inputs/tools/outputs are recorded on\n // the model-call span whenever they are on the parent `invoke_agent` span.\n ...recordingBySpan.get(parent),\n },\n };\n const span = withActiveSpan(parent, () => createSpanFromMessage(message, options));\n // `languageModelCall` always opens a span; the guard just keeps the wrapper safe if that changes.\n if (!span) {\n return Promise.resolve(original.apply(this, args));\n }\n\n // `streamText` ends its operation span synchronously, so its `callId` entry was deliberately left in\n // place for this later model call; drop it now that we've used it.\n const clearStreamCallId = (): void => {\n if (method === 'doStream' && callId) {\n clearOperationCallId(callId);\n }\n };\n\n // Both the synchronous throw and the async rejection of the model call must end the span with an\n // error status (an `async` `doGenerate`/`doStream` that throws rejects rather than throwing here).\n const failSpan = (error: unknown): never => {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: error instanceof Error ? error.message : 'unknown_error' });\n span.end();\n clearStreamCallId();\n throw error;\n };\n\n try {\n const result = Promise.resolve(original.apply(this, args));\n // `doStream` resolves to `{ stream, ... }` before the stream is consumed; we end here (start/end\n // bracket the call) to match the channel timing.\n return result.then(value => {\n message.result = value;\n enrichSpanOnEnd(span, message, options);\n span.end();\n clearStreamCallId();\n return value;\n }, failSpan);\n } catch (error) {\n return failSpan(error);\n }\n };\n}\n\nfunction buildTextMessage(type: 'generateText' | 'streamText'): MessageBuilder {\n return (options, telemetry) => ({\n type,\n event: {\n callId: nextCallId(),\n operationId: `ai.${type}`,\n functionId: asString(telemetry.functionId),\n ...modelFields(options.model),\n maxRetries: options.maxRetries,\n // Normalize to the message-array shape the shared core (and v7's channel) expects: a bare string\n // `prompt` becomes a single user message, matching the SDK's own normalization.\n messages: normalizePromptMessages(options),\n ...recording(telemetry),\n },\n });\n}\n\nfunction normalizePromptMessages(options: Record<string, unknown>): unknown {\n if (Array.isArray(options.messages)) {\n return options.messages;\n }\n if (typeof options.prompt === 'string') {\n return [{ role: 'user', content: options.prompt }];\n }\n return options.messages ?? options.prompt;\n}\n\nfunction recording(telemetry: Record<string, unknown>): { recordInputs: unknown; recordOutputs: unknown } {\n return { recordInputs: telemetry.recordInputs, recordOutputs: telemetry.recordOutputs };\n}\n\nfunction modelFields(model: unknown): { provider?: string; modelId?: string } {\n return { provider: modelField(model, 'provider'), modelId: modelField(model, 'modelId') };\n}\n\nfunction modelField(model: unknown, field: 'modelId' | 'provider'): string | undefined {\n return isRecord(model) ? asString(model[field]) : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"names":["CHANNELS","DEBUG_BUILD","debug","tracingChannel","createSpanFromMessage","bindTracingChannelToSpan","enrichSpanOnEnd","clearOperationId","getActiveSpan","withActiveSpan","clearOperationCallId","SPAN_STATUS_ERROR"],"mappings":"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"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, waitForTracingChannelBinding, debug, _INTERNAL_shouldSkipAiProviderWrapping, resolveAIRecordingOptions, shouldEnableTruncation, extractAnthropicRequestAttributes, GEN_AI_REQUEST_MODEL_ATTRIBUTE, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, addAnthropicRequestAttributes, addAnthropicResponseAttributes, instrumentAsyncIterableStream, instrumentMessageStream } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| import { bindTracingChannelToSpan } from '../../tracing-channel.js'; | ||
| const INTEGRATION_NAME = "Anthropic_AI"; | ||
| const ORIGIN = "auto.ai.orchestrion.anthropic"; | ||
| const INSTRUMENTED_CHANNELS = [ | ||
| { channel: CHANNELS.ANTHROPIC_CHAT, operation: "chat", methodPath: "messages.create", stream: "async-iterable" }, | ||
| { channel: CHANNELS.ANTHROPIC_MODELS, operation: "models", methodPath: "models.retrieve", stream: "none" }, | ||
| { | ||
| channel: CHANNELS.ANTHROPIC_MESSAGES_STREAM, | ||
| operation: "chat", | ||
| methodPath: "messages.stream", | ||
| stream: "message-stream" | ||
| } | ||
| ]; | ||
| let subscribed = false; | ||
| const _anthropicChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel || subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| waitForTracingChannelBinding(() => { | ||
| for (const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS) { | ||
| DEBUG_BUILD && debug.log(`[orchestrion:anthropic] subscribing to channel "${channel}"`); | ||
| bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channel), | ||
| (data) => createGenAiSpan(data, operation, methodPath, options), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| addAnthropicResponseAttributes( | ||
| span, | ||
| data.result, | ||
| resolveAIRecordingOptions(options).recordOutputs | ||
| ); | ||
| }, | ||
| deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, stream, options) | ||
| } | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function createGenAiSpan(data, operation, methodPath, options) { | ||
| const args = data.arguments ?? []; | ||
| if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) { | ||
| return void 0; | ||
| } | ||
| const requestOptions = args[1]; | ||
| if (requestOptions?.headers?.["X-Stainless-Helper-Method"] === "stream") { | ||
| return void 0; | ||
| } | ||
| const params = typeof args[0] === "object" && args[0] !== null ? args[0] : void 0; | ||
| const { recordInputs } = resolveAIRecordingOptions(options); | ||
| const enableTruncation = shouldEnableTruncation(options.enableTruncation); | ||
| const attributes = extractAnthropicRequestAttributes(args, methodPath, operation); | ||
| const model = attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] || "unknown"; | ||
| attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN; | ||
| const span = startInactiveSpan({ | ||
| name: `${operation} ${model}`, | ||
| op: `gen_ai.${operation}`, | ||
| attributes | ||
| }); | ||
| if (recordInputs && params) { | ||
| addAnthropicRequestAttributes(span, params, enableTruncation); | ||
| } | ||
| return span; | ||
| } | ||
| function isAsyncIterable(value) { | ||
| return !!value && typeof value[Symbol.asyncIterator] === "function"; | ||
| } | ||
| function isMessageStream(value) { | ||
| return !!value && typeof value.on === "function"; | ||
| } | ||
| function wrapStreamResult(span, data, stream, options) { | ||
| const { recordOutputs } = resolveAIRecordingOptions(options); | ||
| const result = data.result; | ||
| if (stream === "async-iterable" && isAsyncIterable(result)) { | ||
| const iterate = result[Symbol.asyncIterator].bind(result); | ||
| const instrumented = instrumentAsyncIterableStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs); | ||
| result[Symbol.asyncIterator] = () => instrumented; | ||
| return true; | ||
| } | ||
| if (stream === "message-stream" && isMessageStream(result)) { | ||
| instrumentMessageStream(result, span, recordOutputs); | ||
| return true; | ||
| } | ||
| return false; | ||
| } | ||
| const anthropicChannelIntegration = defineIntegration(_anthropicChannelIntegration); | ||
| export { anthropicChannelIntegration }; | ||
| //# sourceMappingURL=anthropic.js.map |
| {"version":3,"file":"anthropic.js","sources":["../../../../src/integrations/tracing-channel/anthropic.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { AnthropicAiOptions, AnthropicAiResponse, IntegrationFn, Span, SpanAttributeValue } from '@sentry/core';\nimport {\n _INTERNAL_shouldSkipAiProviderWrapping,\n addAnthropicRequestAttributes,\n addAnthropicResponseAttributes,\n debug,\n defineIntegration,\n extractAnthropicRequestAttributes,\n GEN_AI_REQUEST_MODEL_ATTRIBUTE,\n instrumentAsyncIterableStream,\n instrumentMessageStream,\n resolveAIRecordingOptions,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Same name as the OTel integration by design: when enabled, the OTel 'Anthropic_AI'\n// integration is dropped from the default set (see the Node opt-in loader).\nconst INTEGRATION_NAME = 'Anthropic_AI' as const;\n\n// Distinct from the proxy's `auto.ai.anthropic` so spans from the orchestrion path\n// are attributable separately from the OTel/proxy one.\nconst ORIGIN = 'auto.ai.orchestrion.anthropic';\n\n// `stream` determines how the span is ended\nconst INSTRUMENTED_CHANNELS = [\n { channel: CHANNELS.ANTHROPIC_CHAT, operation: 'chat', methodPath: 'messages.create', stream: 'async-iterable' },\n { channel: CHANNELS.ANTHROPIC_MODELS, operation: 'models', methodPath: 'models.retrieve', stream: 'none' },\n {\n channel: CHANNELS.ANTHROPIC_MESSAGES_STREAM,\n operation: 'chat',\n methodPath: 'messages.stream',\n stream: 'message-stream',\n },\n] as const;\n\ntype StreamMode = (typeof INSTRUMENTED_CHANNELS)[number]['stream'];\n\ninterface AnthropicChannelContext {\n arguments: unknown[];\n result?: unknown;\n}\n\nlet subscribed = false;\n\nconst _anthropicChannelIntegration = ((options: AnthropicAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // tracingChannel is unavailable before Node 18.19 and prevent double-subscribe\n if (!diagnosticsChannel.tracingChannel || subscribed) {\n return;\n }\n subscribed = true;\n\n // `bindTracingChannelToSpan` needs the async-context binding that `initOpenTelemetry()` registers\n // after `setupOnce` runs, so wait for it before subscribing.\n waitForTracingChannelBinding(() => {\n for (const { channel, operation, methodPath, stream } of INSTRUMENTED_CHANNELS) {\n DEBUG_BUILD && debug.log(`[orchestrion:anthropic] subscribing to channel \"${channel}\"`);\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<AnthropicChannelContext>(channel),\n data => createGenAiSpan(data, operation, methodPath, options),\n {\n beforeSpanEnd: (span, data) => {\n addAnthropicResponseAttributes(\n span,\n data.result as AnthropicAiResponse,\n resolveAIRecordingOptions(options).recordOutputs,\n );\n },\n deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, stream, options),\n },\n );\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Build the span for an instrumented call.\n * Returning `undefined` opts the payload out so no span is opened.\n */\nfunction createGenAiSpan(\n data: AnthropicChannelContext,\n operation: string,\n methodPath: string,\n options: AnthropicAiOptions,\n): Span | undefined {\n const args = data.arguments ?? [];\n\n // When LangChain (or another provider) is driving the SDK, it records the spans itself and marks this\n // provider as skipped — mirror the OTel integration and don't double-instrument.\n if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) {\n return undefined;\n }\n\n // `messages.stream()` internally calls the instrumented `messages.create({ stream: true })` tagged with\n // an `X-Stainless-Helper-Method: 'stream'` header. The messages-stream channel already covers it, so skip\n // the nested create to avoid a duplicate span.\n const requestOptions = args[1] as { headers?: Record<string, unknown> } | undefined;\n if (requestOptions?.headers?.['X-Stainless-Helper-Method'] === 'stream') {\n return undefined;\n }\n\n const params = typeof args[0] === 'object' && args[0] !== null ? (args[0] as Record<string, unknown>) : undefined;\n\n const { recordInputs } = resolveAIRecordingOptions(options);\n const enableTruncation = shouldEnableTruncation(options.enableTruncation);\n\n const attributes = extractAnthropicRequestAttributes(args, methodPath, operation);\n const model = (attributes[GEN_AI_REQUEST_MODEL_ATTRIBUTE] as string) || 'unknown';\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN;\n\n const span = startInactiveSpan({\n name: `${operation} ${model}`,\n op: `gen_ai.${operation}`,\n attributes: attributes as Record<string, SpanAttributeValue>,\n });\n\n if (recordInputs && params) {\n addAnthropicRequestAttributes(span, params, enableTruncation);\n }\n\n return span;\n}\n\ntype AsyncIterableStream = { [Symbol.asyncIterator]: () => AsyncIterator<unknown> };\ntype MessageStreamEmitter = { on: (...args: unknown[]) => void };\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterableStream {\n return !!value && typeof (value as AsyncIterableStream)[Symbol.asyncIterator] === 'function';\n}\n\nfunction isMessageStream(value: unknown): value is MessageStreamEmitter {\n return !!value && typeof (value as MessageStreamEmitter).on === 'function';\n}\n\n/**\n * Hand span-ending ownership to a streamed result: returns `true` to skip the normal `beforeSpanEnd`,\n * `false` for non-streaming results (which end via `beforeSpanEnd`).\n *\n * - `async-iterable`: patch the `Stream`'s async iterator in place so `instrumentAsyncIterableStream` ends\n * the span when iteration finishes.\n * - `message-stream`: `instrumentMessageStream` attaches `'message'`/`'error'` listeners that end the span.\n */\nfunction wrapStreamResult(\n span: Span,\n data: AnthropicChannelContext,\n stream: StreamMode,\n options: AnthropicAiOptions,\n): boolean {\n const { recordOutputs } = resolveAIRecordingOptions(options);\n const result = data.result;\n\n if (stream === 'async-iterable' && isAsyncIterable(result)) {\n const iterate = result[Symbol.asyncIterator].bind(result);\n const instrumented = instrumentAsyncIterableStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs);\n result[Symbol.asyncIterator] = () => instrumented;\n return true;\n }\n\n if (stream === 'message-stream' && isMessageStream(result)) {\n instrumentMessageStream(result, span, recordOutputs);\n return true;\n }\n\n return false;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven Anthropic integration. Subscribes to the `orchestrion:@anthropic-ai/sdk:*`\n * diagnostics_channels injected into the SDK's chat (`messages`/`completions`/beta `messages`), `models`, and\n * `messages.stream()` methods, so it requires the orchestrion runtime hook or bundler plugin.\n */\nexport const anthropicChannelIntegration = defineIntegration(_anthropicChannelIntegration);\n"],"names":[],"mappings":"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"} |
| const LIFECYCLE_EXT_POINTS = [ | ||
| "onPreAuth", | ||
| "onCredentials", | ||
| "onPostAuth", | ||
| "onPreHandler", | ||
| "onPostHandler", | ||
| "onPreResponse", | ||
| "onRequest" | ||
| ]; | ||
| const handlerPatched = /* @__PURE__ */ Symbol("hapi-handler-patched"); | ||
| const HapiLayerType = { | ||
| ROUTER: "router", | ||
| PLUGIN: "plugin", | ||
| EXT: "server.ext" | ||
| }; | ||
| const HapiLifecycleMethodNames = new Set(LIFECYCLE_EXT_POINTS); | ||
| var AttributeNames = /* @__PURE__ */ ((AttributeNames2) => { | ||
| AttributeNames2["HAPI_TYPE"] = "hapi.type"; | ||
| AttributeNames2["PLUGIN_NAME"] = "hapi.plugin.name"; | ||
| AttributeNames2["EXT_TYPE"] = "server.ext.type"; | ||
| return AttributeNames2; | ||
| })(AttributeNames || {}); | ||
| export { AttributeNames, HapiLayerType, HapiLifecycleMethodNames, handlerPatched }; | ||
| //# sourceMappingURL=hapi-types.js.map |
| {"version":3,"file":"hapi-types.js","sources":["../../../../src/integrations/tracing-channel/hapi-types.ts"],"sourcesContent":["/*\n * Structural type definitions and constants ported from the vendored\n * `@opentelemetry/instrumentation-hapi` types, with all `@hapi/*` and\n * `@opentelemetry/*` dependencies removed. Only the shapes actually accessed by\n * the orchestrion hapi subscriber are kept.\n */\n\n// Single source of truth for the request lifecycle extension points, so the\n// `ServerRequestExtType` union and the runtime `HapiLifecycleMethodNames` set\n// below can't drift apart.\nconst LIFECYCLE_EXT_POINTS = [\n 'onPreAuth',\n 'onCredentials',\n 'onPostAuth',\n 'onPreHandler',\n 'onPostHandler',\n 'onPreResponse',\n 'onRequest',\n] as const;\n\nexport type ServerRequestExtType = (typeof LIFECYCLE_EXT_POINTS)[number];\n\nexport type LifecycleMethod = (request: unknown, h: unknown, err?: Error) => unknown;\n\nexport interface ServerRouteOptions {\n handler?: LifecycleMethod | unknown;\n [key: string]: unknown;\n}\n\nexport interface ServerRoute {\n path: string;\n method: string;\n handler?: LifecycleMethod | unknown;\n options?: ((server: unknown) => ServerRouteOptions) | ServerRouteOptions;\n [key: string]: unknown;\n}\n\nexport interface ServerExtEventsObject {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface ServerExtEventsRequestObject {\n type: ServerRequestExtType;\n method: LifecycleMethod;\n [key: string]: unknown;\n}\n\nexport interface ServerExtOptions {\n [key: string]: unknown;\n}\n\n/**\n * This symbol is used to mark a Hapi route handler or server extension handler as\n * already patched, since it's possible to use these handlers multiple times\n * i.e. when allowing multiple versions of one plugin, or when registering a plugin\n * multiple times on different servers.\n */\nexport const handlerPatched: unique symbol = Symbol('hapi-handler-patched');\n\nexport type PatchableServerRoute = ServerRoute & {\n [handlerPatched]?: boolean;\n};\n\nexport type PatchableExtMethod = LifecycleMethod & {\n [handlerPatched]?: boolean;\n};\n\nexport type ServerExtDirectInput = [ServerRequestExtType, LifecycleMethod, (ServerExtOptions | undefined)?];\n\nexport const HapiLayerType = {\n ROUTER: 'router',\n PLUGIN: 'plugin',\n EXT: 'server.ext',\n} as const;\n\nexport const HapiLifecycleMethodNames = new Set<string>(LIFECYCLE_EXT_POINTS);\n\nexport enum AttributeNames {\n HAPI_TYPE = 'hapi.type',\n PLUGIN_NAME = 'hapi.plugin.name',\n EXT_TYPE = 'server.ext.type',\n}\n"],"names":["AttributeNames"],"mappings":"AAUA,MAAM,oBAAA,GAAuB;AAAA,EAC3B,WAAA;AAAA,EACA,eAAA;AAAA,EACA,YAAA;AAAA,EACA,cAAA;AAAA,EACA,eAAA;AAAA,EACA,eAAA;AAAA,EACA;AACF,CAAA;AAwCO,MAAM,cAAA,0BAAuC,sBAAsB;AAYnE,MAAM,aAAA,GAAgB;AAAA,EAC3B,MAAA,EAAQ,QAAA;AAAA,EACR,MAAA,EAAQ,QAAA;AAAA,EACR,GAAA,EAAK;AACP;AAEO,MAAM,wBAAA,GAA2B,IAAI,GAAA,CAAY,oBAAoB;AAErE,IAAK,cAAA,qBAAAA,eAAAA,KAAL;AACL,EAAAA,gBAAA,WAAA,CAAA,GAAY,WAAA;AACZ,EAAAA,gBAAA,aAAA,CAAA,GAAc,kBAAA;AACd,EAAAA,gBAAA,UAAA,CAAA,GAAW,iBAAA;AAHD,EAAA,OAAAA,eAAAA;AAAA,CAAA,EAAA,cAAA,IAAA,EAAA;;;;"} |
| import { getActiveSpan, getRootSpan, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; | ||
| import { HTTP_ROUTE, HTTP_METHOD } from '@sentry/conventions/attributes'; | ||
| import { handlerPatched, HapiLifecycleMethodNames, HapiLayerType, AttributeNames } from './hapi-types.js'; | ||
| function setHttpServerSpanRouteAttribute(route) { | ||
| const activeSpan = getActiveSpan(); | ||
| if (!activeSpan) { | ||
| return; | ||
| } | ||
| const rootSpan = getRootSpan(activeSpan); | ||
| if (!rootSpan) { | ||
| return; | ||
| } | ||
| if (spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] !== "http.server") { | ||
| return; | ||
| } | ||
| rootSpan.setAttribute(HTTP_ROUTE, route); | ||
| } | ||
| const isLifecycleExtType = (variableToCheck) => { | ||
| return typeof variableToCheck === "string" && HapiLifecycleMethodNames.has(variableToCheck); | ||
| }; | ||
| const isLifecycleExtEventObj = (variableToCheck) => { | ||
| const event = variableToCheck?.type; | ||
| return event !== void 0 && isLifecycleExtType(event); | ||
| }; | ||
| const isDirectExtInput = (variableToCheck) => { | ||
| return Array.isArray(variableToCheck) && variableToCheck.length <= 3 && isLifecycleExtType(variableToCheck[0]) && typeof variableToCheck[1] === "function"; | ||
| }; | ||
| const isPatchableExtMethod = (variableToCheck) => { | ||
| return !Array.isArray(variableToCheck); | ||
| }; | ||
| const getRouteMetadata = (route, pluginName) => { | ||
| const attributes = { | ||
| [HTTP_ROUTE]: route.path, | ||
| // eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes | ||
| [HTTP_METHOD]: route.method | ||
| }; | ||
| let name; | ||
| if (pluginName) { | ||
| attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.PLUGIN; | ||
| attributes[AttributeNames.PLUGIN_NAME] = pluginName; | ||
| name = `${pluginName}: route - ${route.path}`; | ||
| } else { | ||
| attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.ROUTER; | ||
| name = `route - ${route.path}`; | ||
| } | ||
| return { attributes, name }; | ||
| }; | ||
| const getExtMetadata = (extPoint, pluginName, methodName) => { | ||
| let baseName = `ext - ${extPoint}`; | ||
| if (methodName && methodName !== "method") { | ||
| baseName = `ext - ${extPoint} - ${methodName}`; | ||
| } | ||
| if (pluginName) { | ||
| return { | ||
| attributes: { | ||
| [AttributeNames.EXT_TYPE]: extPoint, | ||
| [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT, | ||
| [AttributeNames.PLUGIN_NAME]: pluginName | ||
| }, | ||
| name: `${pluginName}: ${baseName}` | ||
| }; | ||
| } | ||
| return { | ||
| attributes: { | ||
| [AttributeNames.EXT_TYPE]: extPoint, | ||
| [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT | ||
| }, | ||
| name: baseName | ||
| }; | ||
| }; | ||
| function startMetadataSpan(metadata, original) { | ||
| return startSpan( | ||
| { | ||
| name: metadata.name, | ||
| op: `${metadata.attributes[AttributeNames.HAPI_TYPE]}.hapi`, | ||
| attributes: { | ||
| ...metadata.attributes, | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.http.orchestrion.hapi" | ||
| } | ||
| }, | ||
| original | ||
| ); | ||
| } | ||
| function wrapRouteHandler(route, pluginName) { | ||
| if (route[handlerPatched] === true) return route; | ||
| route[handlerPatched] = true; | ||
| const wrapHandler = (oldHandler) => { | ||
| return function(...params) { | ||
| if (!getActiveSpan()) { | ||
| return oldHandler.call(this, ...params); | ||
| } | ||
| setHttpServerSpanRouteAttribute(route.path); | ||
| const metadata = getRouteMetadata(route, pluginName); | ||
| return startMetadataSpan(metadata, () => oldHandler.call(this, ...params)); | ||
| }; | ||
| }; | ||
| if (typeof route.handler === "function") { | ||
| route.handler = wrapHandler(route.handler); | ||
| } else if (typeof route.options === "function") { | ||
| const oldOptions = route.options; | ||
| route.options = function(server) { | ||
| const options = oldOptions(server); | ||
| if (typeof options.handler === "function") { | ||
| options.handler = wrapHandler(options.handler); | ||
| } | ||
| return options; | ||
| }; | ||
| } else if (typeof route.options?.handler === "function") { | ||
| route.options.handler = wrapHandler(route.options.handler); | ||
| } | ||
| return route; | ||
| } | ||
| function wrapExtMethods(method, extPoint, pluginName) { | ||
| if (Array.isArray(method)) { | ||
| for (let i = 0; i < method.length; i++) { | ||
| method[i] = wrapExtMethods(method[i], extPoint); | ||
| } | ||
| return method; | ||
| } else if (isPatchableExtMethod(method)) { | ||
| if (method[handlerPatched] === true) return method; | ||
| method[handlerPatched] = true; | ||
| const newHandler = function(...params) { | ||
| if (!getActiveSpan()) { | ||
| return method.apply(this, params); | ||
| } | ||
| const metadata = getExtMetadata(extPoint, pluginName, method.name); | ||
| return startMetadataSpan(metadata, () => method.apply(void 0, params)); | ||
| }; | ||
| newHandler[handlerPatched] = true; | ||
| return newHandler; | ||
| } | ||
| return method; | ||
| } | ||
| function wrapRouteArguments(args, pluginName) { | ||
| const route = args[0]; | ||
| if (Array.isArray(route)) { | ||
| for (let i = 0; i < route.length; i++) { | ||
| route[i] = wrapRouteHandler(route[i], pluginName); | ||
| } | ||
| } else { | ||
| args[0] = wrapRouteHandler(route, pluginName); | ||
| } | ||
| } | ||
| function wrapExtArguments(args, pluginName) { | ||
| if (Array.isArray(args[0])) { | ||
| const eventsList = args[0]; | ||
| for (let i = 0; i < eventsList.length; i++) { | ||
| const eventObj = eventsList[i]; | ||
| if (isLifecycleExtType(eventObj.type)) { | ||
| const lifecycleEventObj = eventObj; | ||
| const handler = wrapExtMethods(lifecycleEventObj.method, eventObj.type, pluginName); | ||
| lifecycleEventObj.method = handler; | ||
| eventsList[i] = lifecycleEventObj; | ||
| } | ||
| } | ||
| return; | ||
| } else if (isDirectExtInput(args)) { | ||
| const extInput = args; | ||
| const method = extInput[1]; | ||
| const handler = wrapExtMethods(method, extInput[0], pluginName); | ||
| args[1] = handler; | ||
| return; | ||
| } else if (isLifecycleExtEventObj(args[0])) { | ||
| const lifecycleEventObj = args[0]; | ||
| const handler = wrapExtMethods(lifecycleEventObj.method, lifecycleEventObj.type, pluginName); | ||
| lifecycleEventObj.method = handler; | ||
| } | ||
| } | ||
| export { getExtMetadata, getRouteMetadata, wrapExtArguments, wrapRouteArguments }; | ||
| //# sourceMappingURL=hapi-utils.js.map |
| {"version":3,"file":"hapi-utils.js","sources":["../../../../src/integrations/tracing-channel/hapi-utils.ts"],"sourcesContent":["/*\n * OTel-free, `@hapi/*`-free port of the span-building helpers and handler/ext\n * wrap logic from the vendored `@opentelemetry/instrumentation-hapi`\n * (upstream @opentelemetry/instrumentation-hapi@0.64.0). Span output (names,\n * ops, origins, attributes) is kept byte-identical to that instrumentation;\n * span creation goes through the `@sentry/core` API and the OTel active-span\n * guard is replaced with `getActiveSpan()`.\n */\n\nimport {\n getActiveSpan,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n spanToJSON,\n startSpan,\n} from '@sentry/core';\nimport type {\n LifecycleMethod,\n PatchableExtMethod,\n PatchableServerRoute,\n ServerExtDirectInput,\n ServerExtEventsObject,\n ServerExtEventsRequestObject,\n ServerRequestExtType,\n ServerRoute,\n ServerRouteOptions,\n} from './hapi-types';\n// eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes\nimport { HTTP_METHOD, HTTP_ROUTE } from '@sentry/conventions/attributes';\nimport { AttributeNames, handlerPatched, HapiLayerType, HapiLifecycleMethodNames } from './hapi-types';\n\ntype SpanAttributes = Record<string, string | undefined>;\n\ninterface SpanMetadata {\n attributes: SpanAttributes;\n name: string;\n}\n\n/**\n * Set the `http.route` attribute on the root HTTP server span for the current trace.\n *\n * No-op when there is no active span, no root span, or the root span is not an\n * `http.server` span — so framework instrumentations can call this unconditionally\n * without risking attribute pollution on non-HTTP root spans.\n */\nfunction setHttpServerSpanRouteAttribute(route: string): void {\n const activeSpan = getActiveSpan();\n if (!activeSpan) {\n return;\n }\n const rootSpan = getRootSpan(activeSpan);\n if (!rootSpan) {\n return;\n }\n if (spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] !== 'http.server') {\n return;\n }\n rootSpan.setAttribute(HTTP_ROUTE, route);\n}\n\nconst isLifecycleExtType = (variableToCheck: unknown): variableToCheck is ServerRequestExtType => {\n return typeof variableToCheck === 'string' && HapiLifecycleMethodNames.has(variableToCheck);\n};\n\nconst isLifecycleExtEventObj = (variableToCheck: unknown): variableToCheck is ServerExtEventsRequestObject => {\n const event = (variableToCheck as ServerExtEventsRequestObject)?.type;\n return event !== undefined && isLifecycleExtType(event);\n};\n\nconst isDirectExtInput = (variableToCheck: unknown): variableToCheck is ServerExtDirectInput => {\n return (\n Array.isArray(variableToCheck) &&\n variableToCheck.length <= 3 &&\n isLifecycleExtType(variableToCheck[0]) &&\n typeof variableToCheck[1] === 'function'\n );\n};\n\nconst isPatchableExtMethod = (\n variableToCheck: PatchableExtMethod | PatchableExtMethod[],\n): variableToCheck is PatchableExtMethod => {\n return !Array.isArray(variableToCheck);\n};\n\n/** Build the span name and attributes for a Hapi route. */\nexport const getRouteMetadata = (route: ServerRoute, pluginName?: string): SpanMetadata => {\n const attributes: SpanAttributes = {\n [HTTP_ROUTE]: route.path,\n // eslint-disable-next-line typescript/no-deprecated -- TODO(v11): Replace deprecated attributes\n [HTTP_METHOD]: route.method,\n };\n\n let name;\n if (pluginName) {\n attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.PLUGIN;\n attributes[AttributeNames.PLUGIN_NAME] = pluginName;\n name = `${pluginName}: route - ${route.path}`;\n } else {\n attributes[AttributeNames.HAPI_TYPE] = HapiLayerType.ROUTER;\n name = `route - ${route.path}`;\n }\n\n return { attributes, name };\n};\n\n/** Build the span name and attributes for a Hapi server extension. */\nexport const getExtMetadata = (\n extPoint: ServerRequestExtType,\n pluginName?: string,\n methodName?: string,\n): SpanMetadata => {\n let baseName = `ext - ${extPoint}`;\n if (methodName && methodName !== 'method') {\n // `method` is the default name for the extension in the ServerExtEventsObject format.\n baseName = `ext - ${extPoint} - ${methodName}`;\n }\n if (pluginName) {\n return {\n attributes: {\n [AttributeNames.EXT_TYPE]: extPoint,\n [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT,\n [AttributeNames.PLUGIN_NAME]: pluginName,\n },\n name: `${pluginName}: ${baseName}`,\n };\n }\n return {\n attributes: {\n [AttributeNames.EXT_TYPE]: extPoint,\n [AttributeNames.HAPI_TYPE]: HapiLayerType.EXT,\n },\n name: baseName,\n };\n};\n\nfunction startMetadataSpan(metadata: SpanMetadata, original: () => unknown): unknown {\n return startSpan(\n {\n name: metadata.name,\n op: `${metadata.attributes[AttributeNames.HAPI_TYPE]}.hapi`,\n attributes: {\n ...metadata.attributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.orchestrion.hapi',\n },\n },\n original,\n );\n}\n\n/**\n * Patches each individual route handler method in order to create the span. It\n * does not create spans when there is no parent span.\n */\nfunction wrapRouteHandler(route: PatchableServerRoute, pluginName?: string): PatchableServerRoute {\n if (route[handlerPatched] === true) return route;\n route[handlerPatched] = true;\n\n const wrapHandler: (oldHandler: LifecycleMethod) => LifecycleMethod = oldHandler => {\n return function (this: unknown, ...params: Parameters<LifecycleMethod>) {\n if (!getActiveSpan()) {\n return oldHandler.call(this, ...params);\n }\n setHttpServerSpanRouteAttribute(route.path);\n const metadata = getRouteMetadata(route, pluginName);\n return startMetadataSpan(metadata, () => oldHandler.call(this, ...params));\n };\n };\n\n if (typeof route.handler === 'function') {\n route.handler = wrapHandler(route.handler as LifecycleMethod);\n } else if (typeof route.options === 'function') {\n const oldOptions = route.options;\n route.options = function (server: unknown): ServerRouteOptions {\n const options = oldOptions(server);\n if (typeof options.handler === 'function') {\n options.handler = wrapHandler(options.handler as LifecycleMethod);\n }\n return options;\n };\n } else if (typeof route.options?.handler === 'function') {\n route.options.handler = wrapHandler(route.options.handler as LifecycleMethod);\n }\n return route;\n}\n\n/**\n * Wraps request extension methods to add instrumentation to each new extension\n * handler. It does not create spans when there is no parent span.\n */\nfunction wrapExtMethods<T extends PatchableExtMethod | PatchableExtMethod[]>(\n method: T,\n extPoint: ServerRequestExtType,\n pluginName?: string,\n): T {\n if (Array.isArray(method)) {\n for (let i = 0; i < method.length; i++) {\n method[i] = wrapExtMethods(method[i]!, extPoint);\n }\n return method;\n } else if (isPatchableExtMethod(method)) {\n if (method[handlerPatched] === true) return method;\n method[handlerPatched] = true;\n\n const newHandler: PatchableExtMethod = function (this: unknown, ...params: Parameters<LifecycleMethod>) {\n if (!getActiveSpan()) {\n return method.apply(this, params);\n }\n const metadata = getExtMetadata(extPoint, pluginName, method.name);\n return startMetadataSpan(metadata, () => method.apply(undefined, params));\n };\n // Mark the wrapper too (not just the original)\n newHandler[handlerPatched] = true;\n return newHandler as T;\n }\n return method;\n}\n\n/**\n * Wrap the route handler(s) in the live `server.route` arguments array, mutating\n * `args[0]` in place. `args[0]` is either a single route options object or an\n * array of them. Idempotent via the `handlerPatched` marker.\n */\nexport function wrapRouteArguments(args: unknown[], pluginName?: string): void {\n const route = args[0] as PatchableServerRoute | PatchableServerRoute[];\n if (Array.isArray(route)) {\n for (let i = 0; i < route.length; i++) {\n route[i] = wrapRouteHandler(route[i]!, pluginName);\n }\n } else {\n args[0] = wrapRouteHandler(route, pluginName);\n }\n}\n\n/**\n * Wrap the extension method(s) in the live `server.ext` arguments array,\n * mutating `args` in place. Handles the three accepted input shapes:\n * `(eventsArray)`, `(lifecycleEventObject)`, and `(extTypeString, method, options)`.\n * Idempotent via the `handlerPatched` marker.\n */\nexport function wrapExtArguments(args: unknown[], pluginName?: string): void {\n if (Array.isArray(args[0])) {\n const eventsList = args[0] as ServerExtEventsObject[] | ServerExtEventsRequestObject[];\n for (let i = 0; i < eventsList.length; i++) {\n const eventObj = eventsList[i]!;\n if (isLifecycleExtType(eventObj.type)) {\n const lifecycleEventObj = eventObj as ServerExtEventsRequestObject;\n const handler = wrapExtMethods(lifecycleEventObj.method, eventObj.type, pluginName);\n lifecycleEventObj.method = handler;\n eventsList[i] = lifecycleEventObj;\n }\n }\n return;\n } else if (isDirectExtInput(args)) {\n const extInput: ServerExtDirectInput = args;\n const method: PatchableExtMethod = extInput[1];\n const handler = wrapExtMethods(method, extInput[0], pluginName);\n args[1] = handler;\n return;\n } else if (isLifecycleExtEventObj(args[0])) {\n const lifecycleEventObj = args[0];\n const handler = wrapExtMethods(lifecycleEventObj.method, lifecycleEventObj.type, pluginName);\n lifecycleEventObj.method = handler;\n }\n}\n"],"names":[],"mappings":"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"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, debug } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| import { wrapRouteArguments, wrapExtArguments } from './hapi-utils.js'; | ||
| const INTEGRATION_NAME = "Hapi"; | ||
| const _hapiChannelIntegration = (() => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| DEBUG_BUILD && debug.log(`[orchestrion:hapi] subscribing to channels "${CHANNELS.HAPI_ROUTE}" / "${CHANNELS.HAPI_EXT}"`); | ||
| diagnosticsChannel.tracingChannel(CHANNELS.HAPI_ROUTE).subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| wrapRouteArguments(ctx.arguments, ctx.self?.realm?.plugin); | ||
| }, | ||
| end() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| diagnosticsChannel.tracingChannel(CHANNELS.HAPI_EXT).subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| wrapExtArguments(ctx.arguments, ctx.self?.realm?.plugin); | ||
| }, | ||
| end() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const hapiChannelIntegration = defineIntegration(_hapiChannelIntegration); | ||
| export { hapiChannelIntegration }; | ||
| //# sourceMappingURL=hapi.js.map |
| {"version":3,"file":"hapi.js","sources":["../../../../src/integrations/tracing-channel/hapi.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration } from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { wrapExtArguments, wrapRouteArguments } from './hapi-utils';\n\n// NOTE: same name as the OTel integration by design — when enabled, the OTel\n// 'Hapi' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Hapi' as const;\n\n/**\n * The shape orchestrion's transform attaches to the `@hapi/hapi` route/ext\n * tracing-channel `context` objects.\n *\n * `arguments` is the *live* args array passed to `server.route` / `server.ext`;\n * we mutate it in place to swap handlers for span-creating proxies. `self` is\n * the hapi server instance: the root server has `self.realm.plugin === undefined`,\n * while a plugin's clone server exposes the registering plugin's name there.\n */\ninterface HapiChannelContext {\n arguments: unknown[];\n self?: { realm?: { plugin?: string } };\n}\n\nconst _hapiChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD &&\n debug.log(`[orchestrion:hapi] subscribing to channels \"${CHANNELS.HAPI_ROUTE}\" / \"${CHANNELS.HAPI_EXT}\"`);\n\n // `subscribe` requires all five lifecycle hooks. We only act on `start`,\n // which orchestrion fires synchronously with the live args array — that's\n // the moment we mutate the handlers in place.\n diagnosticsChannel.tracingChannel(CHANNELS.HAPI_ROUTE).subscribe({\n start(rawCtx) {\n const ctx = rawCtx as HapiChannelContext;\n wrapRouteArguments(ctx.arguments, ctx.self?.realm?.plugin);\n },\n end() {},\n asyncStart() {},\n asyncEnd() {},\n error() {},\n });\n\n diagnosticsChannel.tracingChannel(CHANNELS.HAPI_EXT).subscribe({\n start(rawCtx) {\n const ctx = rawCtx as HapiChannelContext;\n wrapExtArguments(ctx.arguments, ctx.self?.realm?.plugin);\n },\n end() {},\n asyncStart() {},\n asyncEnd() {},\n error() {},\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * EXPERIMENTAL — orchestrion-driven hapi integration. Subscribes to the\n * `orchestrion:@hapi/hapi:route` / `:ext` channels injected into `@hapi/hapi`'s\n * `lib/server.js`. Requires the orchestrion runtime hook or bundler plugin.\n */\nexport const hapiChannelIntegration = defineIntegration(_hapiChannelIntegration);\n"],"names":[],"mappings":";;;;;;AASA,MAAM,gBAAA,GAAmB,MAAA;AAgBzB,MAAM,2BAA2B,MAAM;AACrC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,IAAI,CAAC,mBAAmB,cAAA,EAAgB;AACtC,QAAA;AAAA,MACF;AAEA,MAAA,WAAA,IACE,KAAA,CAAM,IAAI,CAAA,4CAAA,EAA+C,QAAA,CAAS,UAAU,CAAA,KAAA,EAAQ,QAAA,CAAS,QAAQ,CAAA,CAAA,CAAG,CAAA;AAK1G,MAAA,kBAAA,CAAmB,cAAA,CAAe,QAAA,CAAS,UAAU,CAAA,CAAE,SAAA,CAAU;AAAA,QAC/D,MAAM,MAAA,EAAQ;AACZ,UAAA,MAAM,GAAA,GAAM,MAAA;AACZ,UAAA,kBAAA,CAAmB,GAAA,CAAI,SAAA,EAAW,GAAA,CAAI,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QAC3D,CAAA;AAAA,QACA,GAAA,GAAM;AAAA,QAAC,CAAA;AAAA,QACP,UAAA,GAAa;AAAA,QAAC,CAAA;AAAA,QACd,QAAA,GAAW;AAAA,QAAC,CAAA;AAAA,QACZ,KAAA,GAAQ;AAAA,QAAC;AAAA,OACV,CAAA;AAED,MAAA,kBAAA,CAAmB,cAAA,CAAe,QAAA,CAAS,QAAQ,CAAA,CAAE,SAAA,CAAU;AAAA,QAC7D,MAAM,MAAA,EAAQ;AACZ,UAAA,MAAM,GAAA,GAAM,MAAA;AACZ,UAAA,gBAAA,CAAiB,GAAA,CAAI,SAAA,EAAW,GAAA,CAAI,IAAA,EAAM,OAAO,MAAM,CAAA;AAAA,QACzD,CAAA;AAAA,QACA,GAAA,GAAM;AAAA,QAAC,CAAA;AAAA,QACP,UAAA,GAAa;AAAA,QAAC,CAAA;AAAA,QACd,QAAA,GAAW;AAAA,QAAC,CAAA;AAAA,QACZ,KAAA,GAAQ;AAAA,QAAC;AAAA,OACV,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAOO,MAAM,sBAAA,GAAyB,kBAAkB,uBAAuB;;;;"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { DB_STATEMENT, NET_PEER_PORT, NET_PEER_NAME, DB_SYSTEM } from '@sentry/conventions/attributes'; | ||
| import { defineIntegration, debug, waitForTracingChannelBinding, getActiveSpan, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| import { defaultDbStatementSerializer } from '../../redis/redis-statement-serializer.js'; | ||
| import { bindTracingChannelToSpan } from '../../tracing-channel.js'; | ||
| const INTEGRATION_NAME = "IORedis"; | ||
| const ORIGIN = "auto.db.orchestrion.redis"; | ||
| const ATTR_DB_CONNECTION_STRING = "db.connection_string"; | ||
| function getConnectionOptions(self) { | ||
| return { host: self?.options?.host, port: self?.options?.port }; | ||
| } | ||
| function connectionAttributes(host, port) { | ||
| return { | ||
| [DB_SYSTEM]: "redis", | ||
| [ATTR_DB_CONNECTION_STRING]: `redis://${host}:${port}`, | ||
| [NET_PEER_NAME]: host, | ||
| [NET_PEER_PORT]: port, | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN | ||
| }; | ||
| } | ||
| const _ioredisChannelIntegration = ((options = {}) => { | ||
| const responseHook = options.responseHook; | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| DEBUG_BUILD && debug.log(`[orchestrion:ioredis] subscribing to "${CHANNELS.IOREDIS_COMMAND}"/"${CHANNELS.IOREDIS_CONNECT}"`); | ||
| const commandChannel = diagnosticsChannel.tracingChannel( | ||
| CHANNELS.IOREDIS_COMMAND | ||
| ); | ||
| const connectChannel = diagnosticsChannel.tracingChannel( | ||
| CHANNELS.IOREDIS_CONNECT | ||
| ); | ||
| waitForTracingChannelBinding(() => { | ||
| bindTracingChannelToSpan( | ||
| commandChannel, | ||
| (data) => { | ||
| if (!getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| const command = data.arguments?.[0]; | ||
| if (!command || typeof command !== "object") { | ||
| return void 0; | ||
| } | ||
| const { host, port } = getConnectionOptions(data.self); | ||
| const statement = defaultDbStatementSerializer(command.name, command.args ?? []); | ||
| return startInactiveSpan({ | ||
| name: statement, | ||
| op: "db", | ||
| attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: statement } | ||
| }); | ||
| }, | ||
| { | ||
| beforeSpanEnd(span, data) { | ||
| if ("error" in data || !responseHook) { | ||
| return; | ||
| } | ||
| const command = data.arguments?.[0]; | ||
| if (command) { | ||
| runResponseHook(responseHook, span, command, data.result); | ||
| } | ||
| } | ||
| } | ||
| ); | ||
| bindTracingChannelToSpan(connectChannel, (data) => { | ||
| if (!getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| const { host, port } = getConnectionOptions(data.self); | ||
| return startInactiveSpan({ | ||
| name: "connect", | ||
| op: "db", | ||
| attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: "connect" } | ||
| }); | ||
| }); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function runResponseHook(hook, span, command, result) { | ||
| try { | ||
| hook(span, command.name, command.args, result); | ||
| } catch { | ||
| } | ||
| } | ||
| const ioredisChannelIntegration = defineIntegration(_ioredisChannelIntegration); | ||
| export { ioredisChannelIntegration }; | ||
| //# sourceMappingURL=ioredis.js.map |
| {"version":3,"file":"ioredis.js","sources":["../../../../src/integrations/tracing-channel/ioredis.ts"],"sourcesContent":["/* eslint-disable @typescript-eslint/no-deprecated -- we intentionally emit the OLD db/net semconv\n to match `@opentelemetry/instrumentation-ioredis` (and Sentry's `inferDbSpanData`, which keys off\n `db.statement`). TODO(v11): switch to the non-deprecated `db.system.name`/`db.query.text`/\n `server.address`/`server.port` conventions and drop this disable. */\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { DB_STATEMENT, DB_SYSTEM, NET_PEER_NAME, NET_PEER_PORT } from '@sentry/conventions/attributes';\nimport type { IntegrationFn, Span } from '@sentry/core';\nimport {\n debug,\n defineIntegration,\n getActiveSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { defaultDbStatementSerializer } from '../../redis/redis-statement-serializer';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Distinct from the OTel `Redis` integration, which is composite (node-redis +\n// ioredis + the >=5.11.0 diagnostics_channel subscriber) and stays in the set;\n// only its ioredis monkey-patch is gated off in the node SDK when this is active.\nconst INTEGRATION_NAME = 'IORedis' as const;\n\nconst ORIGIN = 'auto.db.orchestrion.redis';\n\n// todo(v11): Let's drop this as this is already covered with host and port\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\n\n/** Mirrors `@opentelemetry/instrumentation-ioredis`' response hook. Not called for failed commands. */\nexport type IORedisResponseHook = (span: Span, command: string, args: Array<string | Buffer>, result: unknown) => void;\n\nexport interface IORedisChannelIntegrationOptions {\n responseHook?: IORedisResponseHook;\n}\n\n/** Structural type for the command object ioredis passes to `sendCommand`. */\ninterface RedisCommand {\n name: string;\n args: Array<string | Buffer>;\n}\n\ninterface RedisClientLike {\n options?: { host?: string; port?: number };\n}\n\ninterface IORedisCommandContext {\n arguments?: unknown[];\n self?: RedisClientLike;\n result?: unknown;\n error?: unknown;\n}\n\ntype IORedisConnectContext = Omit<IORedisCommandContext, 'arguments'>;\n\nfunction getConnectionOptions(self: RedisClientLike | undefined): { host?: string; port?: number } {\n return { host: self?.options?.host, port: self?.options?.port };\n}\n\nfunction connectionAttributes(host: string | undefined, port: number | undefined): Record<string, unknown> {\n return {\n [DB_SYSTEM]: 'redis',\n [ATTR_DB_CONNECTION_STRING]: `redis://${host}:${port}`,\n [NET_PEER_NAME]: host,\n [NET_PEER_PORT]: port,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n };\n}\n\nconst _ioredisChannelIntegration = ((options: IORedisChannelIntegrationOptions = {}) => {\n const responseHook = options.responseHook;\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD &&\n debug.log(`[orchestrion:ioredis] subscribing to \"${CHANNELS.IOREDIS_COMMAND}\"/\"${CHANNELS.IOREDIS_CONNECT}\"`);\n\n const commandChannel = diagnosticsChannel.tracingChannel<IORedisCommandContext, IORedisCommandContext>(\n CHANNELS.IOREDIS_COMMAND,\n );\n const connectChannel = diagnosticsChannel.tracingChannel<IORedisConnectContext, IORedisConnectContext>(\n CHANNELS.IOREDIS_CONNECT,\n );\n\n // `bindTracingChannelToSpan` uses `bindStore`, which needs the async-context\n // binding that `initOpenTelemetry()` registers after integration `setupOnce` —\n // defer until it's available (matches the native redis diagnostics-channel subscriber).\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n commandChannel,\n data => {\n // ioredis' `requireParentSpan` default: only create a span under an active span.\n if (!getActiveSpan()) {\n return undefined;\n }\n const command = data.arguments?.[0] as RedisCommand | undefined;\n if (!command || typeof command !== 'object') {\n return undefined;\n }\n const { host, port } = getConnectionOptions(data.self);\n const statement = defaultDbStatementSerializer(command.name, command.args ?? []);\n return startInactiveSpan({\n name: statement,\n op: 'db',\n attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: statement },\n });\n },\n {\n beforeSpanEnd(span, data) {\n if ('error' in data || !responseHook) {\n return;\n }\n const command = data.arguments?.[0] as RedisCommand | undefined;\n if (command) {\n runResponseHook(responseHook, span, command, data.result);\n }\n },\n },\n );\n\n bindTracingChannelToSpan(connectChannel, data => {\n if (!getActiveSpan()) {\n return undefined;\n }\n const { host, port } = getConnectionOptions(data.self);\n return startInactiveSpan({\n name: 'connect',\n op: 'db',\n attributes: { ...connectionAttributes(host, port), [DB_STATEMENT]: 'connect' },\n });\n });\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction runResponseHook(hook: IORedisResponseHook, span: Span, command: RedisCommand, result: unknown): void {\n try {\n hook(span, command.name, command.args, result);\n } catch {\n // never let a user-provided response hook break instrumentation\n }\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven ioredis integration. Subscribes to\n * `orchestrion:ioredis:command` / `:connect` (injected into ioredis' `<5.11.0`\n * `sendCommand`/`connect`) and creates db spans matching\n * `@opentelemetry/instrumentation-ioredis`. Requires the orchestrion runtime hook\n * or bundler plugin.\n */\nexport const ioredisChannelIntegration = defineIntegration(_ioredisChannelIntegration);\n"],"names":[],"mappings":"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"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, waitForTracingChannelBinding, debug, _INTERNAL_shouldSkipAiProviderWrapping, resolveAIRecordingOptions, shouldEnableTruncation, extractOpenAiRequestAttributes, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan, addOpenAiRequestAttributes, addOpenAiResponseAttributes, instrumentOpenAiStream } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| import { bindTracingChannelToSpan } from '../../tracing-channel.js'; | ||
| const INTEGRATION_NAME = "OpenAI"; | ||
| const ORIGIN = "auto.ai.orchestrion.openai"; | ||
| const INSTRUMENTED_CHANNELS = [ | ||
| { channel: CHANNELS.OPENAI_CHAT, operation: "chat" }, | ||
| { channel: CHANNELS.OPENAI_RESPONSES, operation: "chat" }, | ||
| { channel: CHANNELS.OPENAI_EMBEDDINGS, operation: "embeddings" }, | ||
| { channel: CHANNELS.OPENAI_CONVERSATIONS, operation: "chat" } | ||
| ]; | ||
| let subscribed = false; | ||
| const _openaiChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel || subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| waitForTracingChannelBinding(() => { | ||
| for (const { channel, operation } of INSTRUMENTED_CHANNELS) { | ||
| DEBUG_BUILD && debug.log(`[orchestrion:openai] subscribing to channel "${channel}"`); | ||
| bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channel), | ||
| (data) => createGenAiSpan(data, operation, options), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| addOpenAiResponseAttributes(span, data.result, resolveAIRecordingOptions(options).recordOutputs); | ||
| }, | ||
| // Streaming: the result is a `Stream` consumed later, so instrument it and let it end the span. | ||
| deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, options) | ||
| } | ||
| ); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function createGenAiSpan(data, operation, options) { | ||
| if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) { | ||
| return void 0; | ||
| } | ||
| const args = data.arguments ?? []; | ||
| const params = args[0]; | ||
| const { recordInputs } = resolveAIRecordingOptions(options); | ||
| const enableTruncation = shouldEnableTruncation(options.enableTruncation); | ||
| const attributes = extractOpenAiRequestAttributes(args, operation); | ||
| attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN; | ||
| const model = params?.model || "unknown"; | ||
| const span = startInactiveSpan({ | ||
| name: `${operation} ${model}`, | ||
| op: `gen_ai.${operation}`, | ||
| attributes | ||
| }); | ||
| if (recordInputs && params) { | ||
| addOpenAiRequestAttributes(span, params, operation, enableTruncation); | ||
| } | ||
| return span; | ||
| } | ||
| function isAsyncIterable(value) { | ||
| return !!value && typeof value[Symbol.asyncIterator] === "function"; | ||
| } | ||
| function wrapStreamResult(span, data, options) { | ||
| const result = data.result; | ||
| if (!isAsyncIterable(result)) { | ||
| return false; | ||
| } | ||
| const { recordOutputs } = resolveAIRecordingOptions(options); | ||
| const iterate = result[Symbol.asyncIterator].bind(result); | ||
| const instrumented = instrumentOpenAiStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs ?? false); | ||
| result[Symbol.asyncIterator] = () => instrumented; | ||
| return true; | ||
| } | ||
| const openaiChannelIntegration = defineIntegration(_openaiChannelIntegration); | ||
| export { openaiChannelIntegration }; | ||
| //# sourceMappingURL=openai.js.map |
| {"version":3,"file":"openai.js","sources":["../../../../src/integrations/tracing-channel/openai.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, OpenAiOptions, Span, SpanAttributeValue } from '@sentry/core';\nimport {\n _INTERNAL_shouldSkipAiProviderWrapping,\n addOpenAiRequestAttributes,\n addOpenAiResponseAttributes,\n debug,\n defineIntegration,\n extractOpenAiRequestAttributes,\n instrumentOpenAiStream,\n resolveAIRecordingOptions,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// Same name as the OTel integration by design: when enabled, the OTel 'OpenAI'\n// integration is dropped from the default set (see the Node opt-in loader).\nconst INTEGRATION_NAME = 'OpenAI' as const;\n\n// Distinct from the proxy's `auto.ai.openai` so spans from the orchestrion path\n// are attributable separately from the OTel/proxy one.\nconst ORIGIN = 'auto.ai.orchestrion.openai';\n\n// Each instrumented `create` method maps to the gen_ai operation its span reports.\nconst INSTRUMENTED_CHANNELS = [\n { channel: CHANNELS.OPENAI_CHAT, operation: 'chat' },\n { channel: CHANNELS.OPENAI_RESPONSES, operation: 'chat' },\n { channel: CHANNELS.OPENAI_EMBEDDINGS, operation: 'embeddings' },\n { channel: CHANNELS.OPENAI_CONVERSATIONS, operation: 'chat' },\n] as const;\n\n/**\n * The context object orchestrion shares across the tracing-channel lifecycle hooks: `arguments` is the\n * live args array passed to `Completions.create(body, options)`, and Node's `tracingChannel` attaches\n * `result` when the returned promise settles.\n */\ninterface OpenAiChatChannelContext {\n arguments: unknown[];\n result?: unknown;\n}\n\nlet subscribed = false;\n\nconst _openaiChannelIntegration = ((options: OpenAiOptions = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19, and a second `init()` would double-subscribe.\n if (!diagnosticsChannel.tracingChannel || subscribed) {\n return;\n }\n subscribed = true;\n\n // `bindTracingChannelToSpan` needs the async-context binding that `initOpenTelemetry()` registers\n // after `setupOnce` runs, so wait for it before subscribing.\n waitForTracingChannelBinding(() => {\n for (const { channel, operation } of INSTRUMENTED_CHANNELS) {\n DEBUG_BUILD && debug.log(`[orchestrion:openai] subscribing to channel \"${channel}\"`);\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<OpenAiChatChannelContext>(channel),\n data => createGenAiSpan(data, operation, options),\n {\n beforeSpanEnd: (span, data) => {\n addOpenAiResponseAttributes(span, data.result, resolveAIRecordingOptions(options).recordOutputs);\n },\n // Streaming: the result is a `Stream` consumed later, so instrument it and let it end the span.\n deferSpanEnd: ({ span, data }) => wrapStreamResult(span, data, options),\n },\n );\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Build the span for an instrumented `create` call.\n * Returning `undefined` opts the payload out so no span is opened.\n */\nfunction createGenAiSpan(data: OpenAiChatChannelContext, operation: string, options: OpenAiOptions): Span | undefined {\n // langchain drives the openai SDK itself and instruments at its own layer; skip here to avoid double spans.\n if (_INTERNAL_shouldSkipAiProviderWrapping(INTEGRATION_NAME)) {\n return undefined;\n }\n\n const args = data.arguments ?? [];\n const params = args[0] as Record<string, unknown> | undefined;\n\n const { recordInputs } = resolveAIRecordingOptions(options);\n const enableTruncation = shouldEnableTruncation(options.enableTruncation);\n\n const attributes = extractOpenAiRequestAttributes(args, operation);\n attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] = ORIGIN;\n const model = (params?.model as string) || 'unknown';\n\n const span = startInactiveSpan({\n name: `${operation} ${model}`,\n op: `gen_ai.${operation}`,\n attributes: attributes as Record<string, SpanAttributeValue>,\n });\n\n if (recordInputs && params) {\n addOpenAiRequestAttributes(span, params, operation, enableTruncation);\n }\n\n return span;\n}\n\ntype AsyncIterableStream = { [Symbol.asyncIterator]: () => AsyncIterator<unknown> };\n\nfunction isAsyncIterable(value: unknown): value is AsyncIterableStream {\n return !!value && typeof (value as AsyncIterableStream)[Symbol.asyncIterator] === 'function';\n}\n\n/**\n * For a streaming `create({ stream: true })` the result is a `Stream` the caller consumes later. We can't\n * swap what `create` returns, but the `Stream` in `data.result` is the same instance the caller holds and\n * `asyncEnd` fires before the caller iterates — so we patch its async iterator in place to run through\n * `instrumentOpenAiStream`, which accumulates the streamed attributes and ends the span when iteration finishes.\n * Only a streaming call resolves to an async-iterable, so that check alone distinguishes it. Returns `true`\n * to hand span-ending ownership to `instrumentOpenAiStream`; `false` for non-streaming/errored results, which end\n * via the normal `beforeSpanEnd` path.\n */\nfunction wrapStreamResult(span: Span, data: OpenAiChatChannelContext, options: OpenAiOptions): boolean {\n const result = data.result;\n if (!isAsyncIterable(result)) {\n return false;\n }\n\n const { recordOutputs } = resolveAIRecordingOptions(options);\n const iterate = result[Symbol.asyncIterator].bind(result);\n const instrumented = instrumentOpenAiStream({ [Symbol.asyncIterator]: iterate }, span, recordOutputs ?? false);\n result[Symbol.asyncIterator] = () => instrumented;\n\n return true;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven OpenAI integration. Subscribes to the `orchestrion:openai:*`\n * diagnostics_channels injected into `openai`'s `create` methods (chat completions, responses, embeddings,\n * conversations), so it requires the orchestrion runtime hook or bundler plugin.\n */\nexport const openaiChannelIntegration = defineIntegration(_openaiChannelIntegration);\n"],"names":[],"mappings":"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"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, waitForTracingChannelBinding, debug, getActiveSpan, getCurrentScope, startInactiveSpan, SPAN_KIND, bindScopeToEmitter, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| import { bindTracingChannelToSpan } from '../../tracing-channel.js'; | ||
| const INTEGRATION_NAME = "Postgres"; | ||
| const ORIGIN = "auto.db.orchestrion.postgres"; | ||
| const ATTR_DB_SYSTEM = "db.system"; | ||
| const ATTR_DB_NAME = "db.name"; | ||
| const ATTR_DB_CONNECTION_STRING = "db.connection_string"; | ||
| const ATTR_DB_USER = "db.user"; | ||
| const ATTR_DB_STATEMENT = "db.statement"; | ||
| const ATTR_NET_PEER_NAME = "net.peer.name"; | ||
| const ATTR_NET_PEER_PORT = "net.peer.port"; | ||
| const ATTR_PG_PLAN = "db.postgresql.plan"; | ||
| const ATTR_PG_IDLE_TIMEOUT = "db.postgresql.idle.timeout.millis"; | ||
| const ATTR_PG_MAX_CLIENT = "db.postgresql.max.client"; | ||
| const DB_SYSTEM_POSTGRESQL = "postgresql"; | ||
| const SPAN_QUERY_FALLBACK = "pg.query"; | ||
| const SPAN_CONNECT = "pg.connect"; | ||
| const SPAN_POOL_CONNECT = "pg-pool.connect"; | ||
| const _postgresChannelIntegration = ((options = {}) => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| waitForTracingChannelBinding(() => { | ||
| subscribeQueryLikeChannel(CHANNELS.PG_QUERY, querySpanOptions, { deferStreamedResult: true }); | ||
| if (!options.ignoreConnectSpans) { | ||
| subscribeQueryLikeChannel(CHANNELS.PG_CONNECT, connectSpanOptions); | ||
| subscribeQueryLikeChannel(CHANNELS.PGPOOL_CONNECT, poolConnectSpanOptions); | ||
| } | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| function subscribeQueryLikeChannel(channelName, getSpanOptions, { deferStreamedResult = false } = {}) { | ||
| DEBUG_BUILD && debug.log(`[orchestrion:pg] subscribing to channel "${channelName}"`); | ||
| bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channelName), | ||
| (data) => { | ||
| if (!getActiveSpan()) { | ||
| return void 0; | ||
| } | ||
| data._sentryCallerScope = getCurrentScope(); | ||
| return startInactiveSpan({ ...getSpanOptions(data), kind: SPAN_KIND.CLIENT }); | ||
| }, | ||
| // `connect`/`pool-connect` resolve with a persistent `Client` (itself an | ||
| // `EventEmitter`), which is NOT a streamed result. Deferring their span | ||
| // to that emitter's `'end'`/`'error'` would keep it open for the whole | ||
| // connection lifetime, so it never ends in time and is dropped. Only | ||
| // `query` can return a streamable `Submittable`, so only it defers. | ||
| deferStreamedResult ? { | ||
| // Streamable `Submittable` (e.g. `client.query(new Query())`) | ||
| // returns an emitter that orchestrion stores on `ctx.result` while | ||
| // firing no async events; the query isn't done until the emitter | ||
| // emits `'end'`/`'error'`. Defer ending to those events for that | ||
| // path; the callback, promise, and sync-throw paths carry no | ||
| // emitter, so the helper ends the span as usual. | ||
| deferSpanEnd({ data, end }) { | ||
| const result = data.result; | ||
| if (!result || typeof result !== "object" || !hasOnMethod(result)) { | ||
| return false; | ||
| } | ||
| const callerScope = data._sentryCallerScope; | ||
| if (callerScope) { | ||
| bindScopeToEmitter(result, callerScope); | ||
| } | ||
| result.on("error", (err) => end(err)); | ||
| result.on("end", () => end()); | ||
| return true; | ||
| } | ||
| } : void 0 | ||
| ); | ||
| } | ||
| function querySpanOptions(ctx) { | ||
| const params = ctx.self?.connectionParameters ?? {}; | ||
| const queryConfig = extractQueryConfig(ctx.arguments); | ||
| return { | ||
| // The description is the SQL statement | ||
| name: queryConfig?.text ?? SPAN_QUERY_FALLBACK, | ||
| op: "db", | ||
| attributes: { | ||
| ...getConnectionAttributes(params), | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [ATTR_DB_STATEMENT]: queryConfig?.text || void 0, | ||
| [ATTR_PG_PLAN]: typeof queryConfig?.name === "string" ? queryConfig.name : void 0 | ||
| } | ||
| }; | ||
| } | ||
| function connectSpanOptions(ctx) { | ||
| const params = ctx.self?.connectionParameters ?? {}; | ||
| return { name: SPAN_CONNECT, op: "db", attributes: getConnectionAttributes(params) }; | ||
| } | ||
| function poolConnectSpanOptions(ctx) { | ||
| const opts = ctx.self?.options ?? {}; | ||
| return { name: SPAN_POOL_CONNECT, op: "db", attributes: getPoolConnectionAttributes(opts) }; | ||
| } | ||
| function hasOnMethod(obj) { | ||
| return "on" in obj && typeof obj.on === "function"; | ||
| } | ||
| function extractQueryConfig(args) { | ||
| const arg0 = args[0]; | ||
| if (typeof arg0 === "string") { | ||
| return { text: arg0 }; | ||
| } | ||
| if (arg0 && typeof arg0 === "object" && typeof arg0.text === "string") { | ||
| const obj = arg0; | ||
| return { text: obj.text, name: obj.name }; | ||
| } | ||
| return void 0; | ||
| } | ||
| function getConnectionAttributes(params) { | ||
| return { | ||
| [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL, | ||
| [ATTR_DB_CONNECTION_STRING]: getConnectionString(params), | ||
| [ATTR_DB_NAME]: params.database, | ||
| [ATTR_DB_USER]: params.user, | ||
| [ATTR_NET_PEER_NAME]: params.host, | ||
| [ATTR_NET_PEER_PORT]: Number.isInteger(params.port) ? params.port : void 0 | ||
| }; | ||
| } | ||
| function getPoolConnectionAttributes(opts) { | ||
| let url; | ||
| try { | ||
| url = opts.connectionString ? new URL(opts.connectionString) : void 0; | ||
| } catch { | ||
| url = void 0; | ||
| } | ||
| const database = url?.pathname.slice(1) || opts.database; | ||
| const host = url?.hostname || opts.host; | ||
| const port = Number(url?.port) || (Number.isInteger(opts.port) ? opts.port : void 0); | ||
| const user = url?.username || opts.user; | ||
| return { | ||
| [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL, | ||
| [ATTR_DB_CONNECTION_STRING]: getConnectionString(opts), | ||
| [ATTR_PG_IDLE_TIMEOUT]: opts.idleTimeoutMillis, | ||
| [ATTR_PG_MAX_CLIENT]: opts.max, | ||
| [ATTR_DB_NAME]: database, | ||
| [ATTR_NET_PEER_PORT]: port, | ||
| // these two come from a url parse and slice, can be '' | ||
| [ATTR_NET_PEER_NAME]: host || void 0, | ||
| [ATTR_DB_USER]: user || void 0 | ||
| }; | ||
| } | ||
| function getConnectionString(params) { | ||
| if (params.connectionString) { | ||
| try { | ||
| const url = new URL(params.connectionString); | ||
| url.username = ""; | ||
| url.password = ""; | ||
| return url.toString(); | ||
| } catch { | ||
| return "postgresql://localhost:5432/"; | ||
| } | ||
| } | ||
| const host = params.host || "localhost"; | ||
| const port = params.port || 5432; | ||
| const database = params.database || ""; | ||
| return `postgresql://${host}:${port}/${database}`; | ||
| } | ||
| const postgresChannelIntegration = defineIntegration(_postgresChannelIntegration); | ||
| export { postgresChannelIntegration }; | ||
| //# sourceMappingURL=postgres.js.map |
| {"version":3,"file":"postgres.js","sources":["../../../../src/integrations/tracing-channel/postgres.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope, SpanAttributes } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getActiveSpan,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_KIND,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, the OTel 'Postgres' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Postgres' as const;\n\n// Only the query span carries an origin (the connect/pool-connect spans don't,\n// so they default to 'manual').\nconst ORIGIN = 'auto.db.orchestrion.postgres';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions, inlined to keep this\n// integration free of `@opentelemetry/*` deps.\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\nconst ATTR_PG_PLAN = 'db.postgresql.plan';\nconst ATTR_PG_IDLE_TIMEOUT = 'db.postgresql.idle.timeout.millis';\nconst ATTR_PG_MAX_CLIENT = 'db.postgresql.max.client';\nconst DB_SYSTEM_POSTGRESQL = 'postgresql';\n\n// We set `op: 'db'` and the SQL description directly here (same as mysql\n// orchestrion) rather than relying on the OTel pipeline's `inferDbSpanData`\n// processor, which only runs in the node SDK, so setting them here is what\n// makes the spans correct on the other runtimes\n//\n// The user-visible span is identical to OTel: query spans are named after\n// `db.statement`; connect/pool-connect spans keep these names.\nconst SPAN_QUERY_FALLBACK = 'pg.query';\nconst SPAN_CONNECT = 'pg.connect';\nconst SPAN_POOL_CONNECT = 'pg-pool.connect';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context`. Documented here rather\n * than imported because orchestrion's runtime doesn't export it.\n */\ninterface PgChannelContext {\n // The live args array passed to the wrapped `query`/`connect` call.\n arguments: unknown[];\n self?: unknown;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto a streamed `Submittable` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface PgConnectionParams {\n database?: string;\n host?: string;\n port?: number;\n user?: string;\n connectionString?: string;\n}\n\ninterface PgPoolOptions extends PgConnectionParams {\n idleTimeoutMillis?: number;\n // pg-pool stores the max pool size as `max` (defaulting it to 10 in its\n // constructor). The OTel pg instrumentation reads a `maxClient` field that\n // pg-pool never sets, so its `db.postgresql.max.client` attribute is always\n // dropped; we read the real `max` so the attribute is actually populated.\n max?: number;\n}\n\nconst _postgresChannelIntegration = ((options: { ignoreConnectSpans?: boolean } = {}) => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n waitForTracingChannelBinding(() => {\n // Query spans: `pg`/native `Client.prototype.query`. Only this channel can return a streamable\n // `Submittable` result, so it's the only one that defers span-ending to the emitter (see below).\n subscribeQueryLikeChannel(CHANNELS.PG_QUERY, querySpanOptions, { deferStreamedResult: true });\n\n // Connect spans, gated by `ignoreConnectSpans` (same as OTel pg).\n // `Client.prototype.connect` (pg + native)\n // and `Pool.prototype.connect` (pg-pool).\n if (!options.ignoreConnectSpans) {\n subscribeQueryLikeChannel(CHANNELS.PG_CONNECT, connectSpanOptions);\n subscribeQueryLikeChannel(CHANNELS.PGPOOL_CONNECT, poolConnectSpanOptions);\n }\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Subscribe to a pg tracing-channel and manage a span across its lifecycle.\n * Shared by the query/connect/pool-connect channels. They differ only in how\n * the span's name + attributes are built (`getSpanOptions`), and whether the\n * result can be a streamable emitter (`deferStreamedResult`, query-only).\n */\nfunction subscribeQueryLikeChannel(\n channelName: string,\n getSpanOptions: (ctx: PgChannelContext) => { name: string; op: string; attributes: SpanAttributes },\n { deferStreamedResult = false }: { deferStreamedResult?: boolean } = {},\n): void {\n DEBUG_BUILD && debug.log(`[orchestrion:pg] subscribing to channel \"${channelName}\"`);\n\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<PgChannelContext>(channelName),\n data => {\n // Only instrument when there's an active span; returning `undefined` opts this call out entirely,\n // leaving the active context untouched (e.g. connects issued during app startup).\n if (!getActiveSpan()) {\n return undefined;\n }\n\n // Capture the caller's scope while still synchronously inside the call, for the streamed path:\n // pg dispatches a `Submittable` emitter's events outside the original async scope, so `deferSpanEnd`\n // replays this scope onto that emitter.\n data._sentryCallerScope = getCurrentScope();\n\n // `kind: CLIENT` mirrors the OTel pg instrumentation, so the emitted\n // `otel.kind` matches across the OTel and diagnostics-channel paths.\n return startInactiveSpan({ ...getSpanOptions(data), kind: SPAN_KIND.CLIENT });\n },\n // `connect`/`pool-connect` resolve with a persistent `Client` (itself an\n // `EventEmitter`), which is NOT a streamed result. Deferring their span\n // to that emitter's `'end'`/`'error'` would keep it open for the whole\n // connection lifetime, so it never ends in time and is dropped. Only\n // `query` can return a streamable `Submittable`, so only it defers.\n deferStreamedResult\n ? {\n // Streamable `Submittable` (e.g. `client.query(new Query())`)\n // returns an emitter that orchestrion stores on `ctx.result` while\n // firing no async events; the query isn't done until the emitter\n // emits `'end'`/`'error'`. Defer ending to those events for that\n // path; the callback, promise, and sync-throw paths carry no\n // emitter, so the helper ends the span as usual.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope onto the emitter so listeners theu\n // user attaches after the call returns (and any spans they start)\n // nest under the caller, not a fresh root trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n }\n : undefined,\n );\n}\n\nfunction querySpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};\n const queryConfig = extractQueryConfig(ctx.arguments);\n return {\n // The description is the SQL statement\n name: queryConfig?.text ?? SPAN_QUERY_FALLBACK,\n op: 'db',\n attributes: {\n ...getConnectionAttributes(params),\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [ATTR_DB_STATEMENT]: queryConfig?.text || undefined,\n [ATTR_PG_PLAN]: typeof queryConfig?.name === 'string' ? queryConfig.name : undefined,\n },\n };\n}\n\nfunction connectSpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const params = (ctx.self as { connectionParameters?: PgConnectionParams } | undefined)?.connectionParameters ?? {};\n // No origin set -> defaults to 'manual'\n return { name: SPAN_CONNECT, op: 'db', attributes: getConnectionAttributes(params) };\n}\n\nfunction poolConnectSpanOptions(ctx: PgChannelContext): { name: string; op: string; attributes: SpanAttributes } {\n const opts = (ctx.self as { options?: PgPoolOptions } | undefined)?.options ?? {};\n return { name: SPAN_POOL_CONNECT, op: 'db', attributes: getPoolConnectionAttributes(opts) };\n}\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\n// `client.query(text, cb?)`, `client.query(text, values, cb?)`, and\n// `client.query(configObj, cb?)` are all valid; normalize to `{ text, name }`\n// (the only fields the span needs). Returns undefined for invalid args.\nfunction extractQueryConfig(args: unknown[]): { text: string; name?: unknown } | undefined {\n const arg0 = args[0];\n if (typeof arg0 === 'string') {\n return { text: arg0 };\n }\n if (arg0 && typeof arg0 === 'object' && typeof (arg0 as { text?: unknown }).text === 'string') {\n const obj = arg0 as { text: string; name?: unknown };\n return { text: obj.text, name: obj.name };\n }\n return undefined;\n}\n\nfunction getConnectionAttributes(params: PgConnectionParams): SpanAttributes {\n return {\n [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL,\n [ATTR_DB_CONNECTION_STRING]: getConnectionString(params),\n [ATTR_DB_NAME]: params.database,\n [ATTR_DB_USER]: params.user,\n [ATTR_NET_PEER_NAME]: params.host,\n [ATTR_NET_PEER_PORT]: Number.isInteger(params.port) ? params.port : undefined,\n };\n}\n\nfunction getPoolConnectionAttributes(opts: PgPoolOptions): SpanAttributes {\n let url: URL | undefined;\n try {\n url = opts.connectionString ? new URL(opts.connectionString) : undefined;\n } catch {\n url = undefined;\n }\n const database = url?.pathname.slice(1) || opts.database;\n const host = url?.hostname || opts.host;\n // Mirror OTel's `getSemanticAttributesFromPoolConnection`: prefer the URL's\n // port, but fall back to an explicit `opts.port` when the connection string\n // omits it (`Number('')` / `Number(undefined)` -> falsy).\n const port = Number(url?.port) || (Number.isInteger(opts.port) ? opts.port : undefined);\n const user = url?.username || opts.user;\n return {\n [ATTR_DB_SYSTEM]: DB_SYSTEM_POSTGRESQL,\n [ATTR_DB_CONNECTION_STRING]: getConnectionString(opts),\n [ATTR_PG_IDLE_TIMEOUT]: opts.idleTimeoutMillis,\n [ATTR_PG_MAX_CLIENT]: opts.max,\n [ATTR_DB_NAME]: database,\n [ATTR_NET_PEER_PORT]: port,\n // these two come from a url parse and slice, can be ''\n [ATTR_NET_PEER_NAME]: host || undefined,\n [ATTR_DB_USER]: user || undefined,\n };\n}\n\n// Builds `postgresql://host:port/database`, masking credentials when a raw\n// connection string was provided.\nfunction getConnectionString(params: PgConnectionParams): string {\n if (params.connectionString) {\n try {\n const url = new URL(params.connectionString);\n url.username = '';\n url.password = '';\n return url.toString();\n } catch {\n return 'postgresql://localhost:5432/';\n }\n }\n const host = params.host || 'localhost';\n const port = params.port || 5432;\n const database = params.database || '';\n return `postgresql://${host}:${port}/${database}`;\n}\n\n/**\n * EXPERIMENTAL: orchestrion-driven `pg` (node-postgres) integration.\n *\n * Subscribes to the `orchestrion:pg:query`/`:connect` and\n * `orchestrion:pg-pool:connect` diagnostics_channels that the orchestrion code\n * transform injects into `pg`'s `Client.prototype.query`/`connect`\n * and `pg-pool`'s `Pool.prototype.connect`. Requires the orchestrion runtime\n * hook or bundler plugin to be active.\n */\nexport const postgresChannelIntegration = defineIntegration(_postgresChannelIntegration);\n"],"names":[],"mappings":"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"} |
| import { defineIntegration, extendIntegration, waitForTracingChannelBinding } from '@sentry/core'; | ||
| import { vercelAiIntegration } from '../../vercel-ai/index.js'; | ||
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { subscribeVercelAiOrchestrionChannels } from '../../vercel-ai/vercel-ai-orchestrion-v6-subscriber.js'; | ||
| const _vercelAiChannelIntegration = ((options = {}) => { | ||
| const parentIntegration = vercelAiIntegration(options); | ||
| return extendIntegration(parentIntegration, { | ||
| options, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| waitForTracingChannelBinding(() => { | ||
| subscribeVercelAiOrchestrionChannels(diagnosticsChannel.tracingChannel, options); | ||
| }); | ||
| } | ||
| }); | ||
| }); | ||
| const vercelAiChannelIntegration = defineIntegration(_vercelAiChannelIntegration); | ||
| export { vercelAiChannelIntegration }; | ||
| //# sourceMappingURL=vercel-ai.js.map |
| {"version":3,"file":"vercel-ai.js","sources":["../../../../src/integrations/tracing-channel/vercel-ai.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration, extendIntegration, waitForTracingChannelBinding } from '@sentry/core';\nimport { vercelAiIntegration as baseVercelAiIntegration } from '../../vercel-ai';\nimport * as dc from 'node:diagnostics_channel';\nimport { subscribeVercelAiOrchestrionChannels } from '../../vercel-ai/vercel-ai-orchestrion-v6-subscriber';\n\ntype VercelAiOptions = Parameters<typeof baseVercelAiIntegration>[0];\n\n// In channel-based (orchestrion) mode we emit our own `gen_ai.*` spans from the\n// diagnostics channels. The `ai` SDK would otherwise emit its own native\n// OpenTelemetry spans whenever the user enables `experimental_telemetry`, which\n// would be duplicates. Rather than dropping those after the fact, the v6\n// subscriber suppresses them at the source: it flips the wrapped call's\n// `experimental_telemetry.isEnabled` to `false`, so `ai` falls back to its\n// internal no-op tracer and never creates the native spans in the first place.\n// See `subscribeVercelAiOrchestrionChannels`.\nconst _vercelAiChannelIntegration = ((options: VercelAiOptions = {}) => {\n const parentIntegration = baseVercelAiIntegration(options);\n\n return extendIntegration(parentIntegration, {\n options,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n waitForTracingChannelBinding(() => {\n subscribeVercelAiOrchestrionChannels(dc.tracingChannel, options);\n });\n },\n });\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK. Supported are:\n * - v7 via native `ai:telemetry` tracing channel\n * - v6 via orchestrion `orchestrion:ai:*` channels\n */\nexport const vercelAiChannelIntegration = defineIntegration(_vercelAiChannelIntegration);\n"],"names":["baseVercelAiIntegration","dc"],"mappings":";;;;;AAgBA,MAAM,2BAAA,IAA+B,CAAC,OAAA,GAA2B,EAAC,KAAM;AACtE,EAAA,MAAM,iBAAA,GAAoBA,oBAAwB,OAAO,CAAA;AAEzD,EAAA,OAAO,kBAAkB,iBAAA,EAAmB;AAAA,IAC1C,OAAA;AAAA,IACA,SAAA,GAAY;AAEV,MAAA,IAAI,CAACC,mBAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAEA,MAAA,4BAAA,CAA6B,MAAM;AACjC,QAAA,oCAAA,CAAqCA,kBAAA,CAAG,gBAAgB,OAAO,CAAA;AAAA,MACjE,CAAC,CAAA;AAAA,IACH;AAAA,GACD,CAAA;AACH,CAAA,CAAA;AAOO,MAAM,0BAAA,GAA6B,kBAAkB,2BAA2B;;;;"} |
| import { defineIntegration, waitForTracingChannelBinding } from '@sentry/core'; | ||
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { subscribeMongooseDiagnosticChannels } from './mongoose-dc-subscriber.js'; | ||
| const _mongooseIntegration = (() => { | ||
| return { | ||
| name: "Mongoose", | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| waitForTracingChannelBinding(() => { | ||
| subscribeMongooseDiagnosticChannels(diagnosticsChannel.tracingChannel); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const mongooseIntegration = defineIntegration(_mongooseIntegration); | ||
| export { mongooseIntegration }; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../src/mongoose/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn, waitForTracingChannelBinding } from '@sentry/core';\nimport * as dc from 'node:diagnostics_channel';\nimport { subscribeMongooseDiagnosticChannels } from './mongoose-dc-subscriber';\n\nconst _mongooseIntegration = (() => {\n return {\n name: 'Mongoose',\n setupOnce() {\n // Bail on Node <= 18.18.0, where `tracingChannel` does not exist.\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to mongoose's native tracing channels (mongoose >= 9.7).\n // This is a no-op on versions that don't publish to the channels, so it is always safe to call.\n waitForTracingChannelBinding(() => {\n subscribeMongooseDiagnosticChannels(dc.tracingChannel);\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the [mongoose](https://www.npmjs.com/package/mongoose) library via its native\n * `node:diagnostics_channel` tracing channels (mongoose >= 9.7).\n *\n * On older mongoose versions the channels are never published to, so this integration is inert and\n * the IITM-based patcher (gated to `< 9.7.0`) handles instrumentation instead.\n */\nexport const mongooseIntegration = defineIntegration(_mongooseIntegration);\n"],"names":["dc"],"mappings":";;;;AAIA,MAAM,wBAAwB,MAAM;AAClC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAACA,mBAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAIA,MAAA,4BAAA,CAA6B,MAAM;AACjC,QAAA,mCAAA,CAAoCA,mBAAG,cAAc,CAAA;AAAA,MACvD,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AASO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"} |
| import { SERVER_PORT, SERVER_ADDRESS, DB_OPERATION_BATCH_SIZE, DB_QUERY_TEXT, DB_NAMESPACE, DB_COLLECTION_NAME, DB_OPERATION_NAME, DB_SYSTEM_NAME } from '@sentry/conventions/attributes'; | ||
| import { debug, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../debug-build.js'; | ||
| import { bindTracingChannelToSpan } from '../tracing-channel.js'; | ||
| const MONGOOSE_DC_CHANNEL_QUERY = "mongoose:query"; | ||
| const MONGOOSE_DC_CHANNEL_AGGREGATE = "mongoose:aggregate"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_SAVE = "mongoose:model:save"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = "mongoose:model:insertMany"; | ||
| const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = "mongoose:model:bulkWrite"; | ||
| const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = "mongoose:cursor:next"; | ||
| const ORIGIN = "auto.db.mongoose.diagnostic_channel"; | ||
| const DB_SYSTEM_NAME_VALUE_MONGODB = "mongodb"; | ||
| const MAX_REDACTION_DEPTH = 10; | ||
| let subscribed = false; | ||
| function subscribeMongooseDiagnosticChannels(tracingChannel) { | ||
| if (subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| try { | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_QUERY); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_AGGREGATE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_SAVE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE); | ||
| setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_CURSOR_NEXT); | ||
| } catch { | ||
| DEBUG_BUILD && debug.log("Mongoose node:diagnostics_channel subscription failed."); | ||
| } | ||
| } | ||
| function setupChannel(tracingChannel, channelName) { | ||
| bindTracingChannelToSpan(tracingChannel(channelName), (data) => { | ||
| const collection = data.collection; | ||
| const queryText = redactMongoQuery(data.args?.pipeline ?? data.args?.filter); | ||
| const batchSize = getBatchSize(data); | ||
| return startInactiveSpan({ | ||
| name: collection ? `mongoose.${collection}.${data.operation}` : `mongoose.${data.operation}`, | ||
| attributes: { | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_OP]: "db", | ||
| [DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_MONGODB, | ||
| [DB_OPERATION_NAME]: data.operation, | ||
| [DB_COLLECTION_NAME]: collection ?? void 0, | ||
| [DB_NAMESPACE]: data.database ?? void 0, | ||
| [DB_QUERY_TEXT]: queryText ?? void 0, | ||
| [DB_OPERATION_BATCH_SIZE]: batchSize ?? void 0, | ||
| [SERVER_ADDRESS]: data.serverAddress ?? void 0, | ||
| [SERVER_PORT]: data.serverPort ?? void 0 | ||
| } | ||
| }); | ||
| }); | ||
| } | ||
| function getBatchSize(data) { | ||
| const args = data.args; | ||
| const batch = data.operation === "insertMany" ? args?.docs : data.operation === "bulkWrite" ? args?.ops : void 0; | ||
| return Array.isArray(batch) && batch.length > 1 ? batch.length : void 0; | ||
| } | ||
| function redactMongoQuery(value) { | ||
| if (value == null) { | ||
| return void 0; | ||
| } | ||
| try { | ||
| const redacted = redactValue(value, 0); | ||
| const text = JSON.stringify(redacted); | ||
| return text == null || text === "{}" || text === "[]" ? void 0 : text; | ||
| } catch { | ||
| return void 0; | ||
| } | ||
| } | ||
| function redactValue(value, depth) { | ||
| if (depth > MAX_REDACTION_DEPTH) { | ||
| return "?"; | ||
| } | ||
| if (Array.isArray(value)) { | ||
| return value.map((item) => redactValue(item, depth + 1)); | ||
| } | ||
| if (value && typeof value === "object") { | ||
| const out = {}; | ||
| for (const key of Object.keys(value)) { | ||
| out[key] = redactValue(value[key], depth + 1); | ||
| } | ||
| return out; | ||
| } | ||
| return "?"; | ||
| } | ||
| export { MONGOOSE_DC_CHANNEL_AGGREGATE, MONGOOSE_DC_CHANNEL_CURSOR_NEXT, MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE, MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY, MONGOOSE_DC_CHANNEL_MODEL_SAVE, MONGOOSE_DC_CHANNEL_QUERY, subscribeMongooseDiagnosticChannels }; | ||
| //# sourceMappingURL=mongoose-dc-subscriber.js.map |
| {"version":3,"file":"mongoose-dc-subscriber.js","sources":["../../../src/mongoose/mongoose-dc-subscriber.ts"],"sourcesContent":["import type { TracingChannel } from 'node:diagnostics_channel';\nimport {\n DB_COLLECTION_NAME,\n DB_NAMESPACE,\n DB_OPERATION_BATCH_SIZE,\n DB_OPERATION_NAME,\n DB_QUERY_TEXT,\n DB_SYSTEM_NAME,\n SERVER_ADDRESS,\n SERVER_PORT,\n} from '@sentry/conventions/attributes';\nimport { debug, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n// Channel names published by mongoose >= 9.7.0 (see mongoose `lib/tracing.js`,\n// `lib/query.js`, `lib/aggregate.js`, `lib/model.js` and `lib/cursor/*`).\n// Hardcoded so the subscriber does not have to import mongoose — the channels\n// just have to be subscribed to before the user's mongoose code publishes.\nexport const MONGOOSE_DC_CHANNEL_QUERY = 'mongoose:query';\nexport const MONGOOSE_DC_CHANNEL_AGGREGATE = 'mongoose:aggregate';\nexport const MONGOOSE_DC_CHANNEL_MODEL_SAVE = 'mongoose:model:save';\nexport const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = 'mongoose:model:insertMany';\nexport const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = 'mongoose:model:bulkWrite';\nexport const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = 'mongoose:cursor:next';\n\nconst ORIGIN = 'auto.db.mongoose.diagnostic_channel';\nconst DB_SYSTEM_NAME_VALUE_MONGODB = 'mongodb';\n\n// Cap recursion so a self-referential or pathologically deep query can never\n// stall (or blow the stack in) instrumentation.\nconst MAX_REDACTION_DEPTH = 10;\n\n/**\n * Shape of the context object mongoose >= 9.7.0 publishes on its tracing\n * channels (mongoose's `TracingContext`, see `types/tracing.d.ts`).\n *\n * Node's `tracePromise` mutates this same object with `result`/`error` once the\n * operation settles, which `bindTracingChannelToSpan` reads in its lifecycle\n * handlers — hence both are declared optional here.\n *\n * Unlike redis/ioredis, mongoose does NOT pre-sanitize the payload, so `args`\n * carries the raw user query. We redact it before emitting `db.query.text`.\n */\nexport interface MongooseTracingData {\n operation: string;\n /** Absent for connection-level `aggregate()` calls, which have no model/collection. */\n collection?: string;\n database?: string;\n serverAddress?: string;\n serverPort?: number;\n /** Cursor channels only: the cursor's fetch batch size and tailable flag. */\n batchSize?: number;\n tailable?: boolean;\n /**\n * Operation-specific arguments. `filter` (queries/cursors) and `pipeline`\n * (aggregations) carry the query shape; `docs`/`ops` carry batch payloads.\n */\n args?: {\n filter?: unknown;\n pipeline?: unknown;\n docs?: unknown;\n ops?: unknown;\n [key: string]: unknown;\n };\n result?: unknown;\n error?: Error;\n}\n\n/**\n * Platform-provided factory that creates a native tracing channel for the given name. The\n * subscriber binds the span and its lifecycle onto the channel via `bindTracingChannelToSpan`,\n * which propagates the active span through the runtime's async context.\n *\n * Node passes `node:diagnostics_channel`'s `tracingChannel` directly.\n */\nexport type MongooseTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to mongoose's diagnostics-channel events\n * (`mongoose:query`, `:aggregate`, `:model:save`, `:model:insertMany`,\n * `:model:bulkWrite`, `:cursor:next`), published by mongoose >= 9.7.0.\n *\n * On older mongoose versions the channels are never published to, so the\n * subscribers are inert — there is no double-instrumentation against the\n * IITM-based vendored patcher, which is gated to `< 9.7.0`.\n *\n * Idempotent: subsequent calls are a no-op.\n */\nexport function subscribeMongooseDiagnosticChannels(tracingChannel: MongooseTracingChannelFactory): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n try {\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_QUERY);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_AGGREGATE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_SAVE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE);\n setupChannel(tracingChannel, MONGOOSE_DC_CHANNEL_CURSOR_NEXT);\n } catch {\n // The factory relies on `node:diagnostics_channel`, which isn't always\n // available. Fail closed; the SDK simply won't emit mongoose spans here.\n DEBUG_BUILD && debug.log('Mongoose node:diagnostics_channel subscription failed.');\n }\n}\n\nfunction setupChannel(tracingChannel: MongooseTracingChannelFactory, channelName: string): void {\n bindTracingChannelToSpan(tracingChannel<MongooseTracingData>(channelName), data => {\n const collection = data.collection;\n const queryText = redactMongoQuery(data.args?.pipeline ?? data.args?.filter);\n const batchSize = getBatchSize(data);\n\n return startInactiveSpan({\n name: collection ? `mongoose.${collection}.${data.operation}` : `mongoose.${data.operation}`,\n attributes: {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'db',\n [DB_SYSTEM_NAME]: DB_SYSTEM_NAME_VALUE_MONGODB,\n [DB_OPERATION_NAME]: data.operation,\n [DB_COLLECTION_NAME]: collection ?? undefined,\n [DB_NAMESPACE]: data.database ?? undefined,\n [DB_QUERY_TEXT]: queryText ?? undefined,\n [DB_OPERATION_BATCH_SIZE]: batchSize ?? undefined,\n [SERVER_ADDRESS]: data.serverAddress ?? undefined,\n [SERVER_PORT]: data.serverPort ?? undefined,\n },\n });\n });\n}\n\n/**\n * `db.operation.batch.size` is only meaningful for genuine batch operations.\n * Mongoose's cursor `batchSize` is a fetch-tuning option, not a batch operation\n * size, so it is intentionally excluded here.\n */\nfunction getBatchSize(data: MongooseTracingData): number | undefined {\n const args = data.args;\n const batch = data.operation === 'insertMany' ? args?.docs : data.operation === 'bulkWrite' ? args?.ops : undefined;\n\n return Array.isArray(batch) && batch.length > 1 ? batch.length : undefined;\n}\n\n/**\n * Serialize a mongoose filter/pipeline into `db.query.text` while stripping every\n * value: keys and Mongo operators (`$gt`, `$in`, …) are preserved, leaf values\n * become `'?'`. Mongoose does not sanitize its channel payload, so this prevents\n * raw user data (potential PII) from leaving the process. Returns `undefined`\n * (rather than throwing) on anything it cannot serialize.\n */\nfunction redactMongoQuery(value: unknown): string | undefined {\n if (value == null) {\n return undefined;\n }\n\n try {\n const redacted = redactValue(value, 0);\n const text = JSON.stringify(redacted);\n\n // Skip empty/uninformative shapes (e.g. a `findOne()` with no filter).\n return text == null || text === '{}' || text === '[]' ? undefined : text;\n } catch {\n return undefined;\n }\n}\n\nfunction redactValue(value: unknown, depth: number): unknown {\n if (depth > MAX_REDACTION_DEPTH) {\n return '?';\n }\n\n if (Array.isArray(value)) {\n return value.map(item => redactValue(item, depth + 1));\n }\n\n if (value && typeof value === 'object') {\n const out: Record<string, unknown> = {};\n for (const key of Object.keys(value as Record<string, unknown>)) {\n out[key] = redactValue((value as Record<string, unknown>)[key], depth + 1);\n }\n\n return out;\n }\n\n return '?';\n}\n"],"names":[],"mappings":";;;;;AAmBO,MAAM,yBAAA,GAA4B;AAClC,MAAM,6BAAA,GAAgC;AACtC,MAAM,8BAAA,GAAiC;AACvC,MAAM,qCAAA,GAAwC;AAC9C,MAAM,oCAAA,GAAuC;AAC7C,MAAM,+BAAA,GAAkC;AAE/C,MAAM,MAAA,GAAS,qCAAA;AACf,MAAM,4BAAA,GAA+B,SAAA;AAIrC,MAAM,mBAAA,GAAsB,EAAA;AA+C5B,IAAI,UAAA,GAAa,KAAA;AAaV,SAAS,oCAAoC,cAAA,EAAqD;AACvG,EAAA,IAAI,UAAA,EAAY;AACd,IAAA;AAAA,EACF;AACA,EAAA,UAAA,GAAa,IAAA;AAEb,EAAA,IAAI;AACF,IAAA,YAAA,CAAa,gBAAgB,yBAAyB,CAAA;AACtD,IAAA,YAAA,CAAa,gBAAgB,6BAA6B,CAAA;AAC1D,IAAA,YAAA,CAAa,gBAAgB,8BAA8B,CAAA;AAC3D,IAAA,YAAA,CAAa,gBAAgB,qCAAqC,CAAA;AAClE,IAAA,YAAA,CAAa,gBAAgB,oCAAoC,CAAA;AACjE,IAAA,YAAA,CAAa,gBAAgB,+BAA+B,CAAA;AAAA,EAC9D,CAAA,CAAA,MAAQ;AAGN,IAAA,WAAA,IAAe,KAAA,CAAM,IAAI,wDAAwD,CAAA;AAAA,EACnF;AACF;AAEA,SAAS,YAAA,CAAa,gBAA+C,WAAA,EAA2B;AAC9F,EAAA,wBAAA,CAAyB,cAAA,CAAoC,WAAW,CAAA,EAAG,CAAA,IAAA,KAAQ;AACjF,IAAA,MAAM,aAAa,IAAA,CAAK,UAAA;AACxB,IAAA,MAAM,YAAY,gBAAA,CAAiB,IAAA,CAAK,MAAM,QAAA,IAAY,IAAA,CAAK,MAAM,MAAM,CAAA;AAC3E,IAAA,MAAM,SAAA,GAAY,aAAa,IAAI,CAAA;AAEnC,IAAA,OAAO,iBAAA,CAAkB;AAAA,MACvB,IAAA,EAAM,UAAA,GAAa,CAAA,SAAA,EAAY,UAAU,CAAA,CAAA,EAAI,KAAK,SAAS,CAAA,CAAA,GAAK,CAAA,SAAA,EAAY,IAAA,CAAK,SAAS,CAAA,CAAA;AAAA,MAC1F,UAAA,EAAY;AAAA,QACV,CAAC,gCAAgC,GAAG,MAAA;AAAA,QACpC,CAAC,4BAA4B,GAAG,IAAA;AAAA,QAChC,CAAC,cAAc,GAAG,4BAAA;AAAA,QAClB,CAAC,iBAAiB,GAAG,IAAA,CAAK,SAAA;AAAA,QAC1B,CAAC,kBAAkB,GAAG,UAAA,IAAc,MAAA;AAAA,QACpC,CAAC,YAAY,GAAG,IAAA,CAAK,QAAA,IAAY,MAAA;AAAA,QACjC,CAAC,aAAa,GAAG,SAAA,IAAa,MAAA;AAAA,QAC9B,CAAC,uBAAuB,GAAG,SAAA,IAAa,MAAA;AAAA,QACxC,CAAC,cAAc,GAAG,IAAA,CAAK,aAAA,IAAiB,MAAA;AAAA,QACxC,CAAC,WAAW,GAAG,IAAA,CAAK,UAAA,IAAc;AAAA;AACpC,KACD,CAAA;AAAA,EACH,CAAC,CAAA;AACH;AAOA,SAAS,aAAa,IAAA,EAA+C;AACnE,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,SAAA,KAAc,YAAA,GAAe,IAAA,EAAM,OAAO,IAAA,CAAK,SAAA,KAAc,WAAA,GAAc,IAAA,EAAM,GAAA,GAAM,MAAA;AAE1G,EAAA,OAAO,KAAA,CAAM,QAAQ,KAAK,CAAA,IAAK,MAAM,MAAA,GAAS,CAAA,GAAI,MAAM,MAAA,GAAS,MAAA;AACnE;AASA,SAAS,iBAAiB,KAAA,EAAoC;AAC5D,EAAA,IAAI,SAAS,IAAA,EAAM;AACjB,IAAA,OAAO,MAAA;AAAA,EACT;AAEA,EAAA,IAAI;AACF,IAAA,MAAM,QAAA,GAAW,WAAA,CAAY,KAAA,EAAO,CAAC,CAAA;AACrC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,SAAA,CAAU,QAAQ,CAAA;AAGpC,IAAA,OAAO,QAAQ,IAAA,IAAQ,IAAA,KAAS,IAAA,IAAQ,IAAA,KAAS,OAAO,KAAA,CAAA,GAAY,IAAA;AAAA,EACtE,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,WAAA,CAAY,OAAgB,KAAA,EAAwB;AAC3D,EAAA,IAAI,QAAQ,mBAAA,EAAqB;AAC/B,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,IAAA,OAAO,MAAM,GAAA,CAAI,CAAA,IAAA,KAAQ,YAAY,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAC,CAAA;AAAA,EACvD;AAEA,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,EAAU;AACtC,IAAA,MAAM,MAA+B,EAAC;AACtC,IAAA,KAAA,MAAW,GAAA,IAAO,MAAA,CAAO,IAAA,CAAK,KAAgC,CAAA,EAAG;AAC/D,MAAA,GAAA,CAAI,GAAG,CAAA,GAAI,WAAA,CAAa,MAAkC,GAAG,CAAA,EAAG,QAAQ,CAAC,CAAA;AAAA,IAC3E;AAEA,IAAA,OAAO,GAAA;AAAA,EACT;AAEA,EAAA,OAAO,GAAA;AACT;;;;"} |
| const anthropicAiConfig = [ | ||
| // One entry each for CJS/ESM | ||
| ...["resources/messages/messages.js", "resources/messages/messages.mjs"].flatMap( | ||
| (filePath) => ["create", "countTokens"].map((methodName) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName, kind: "Auto" } | ||
| })) | ||
| ), | ||
| ...["resources/completions.js", "resources/completions.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Completions", methodName: "create", kind: "Auto" } | ||
| })), | ||
| ...["resources/beta/messages/messages.js", "resources/beta/messages/messages.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName: "create", kind: "Auto" } | ||
| })), | ||
| ...["resources/models.js", "resources/models.mjs"].map((filePath) => ({ | ||
| channelName: "models", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Models", methodName: "retrieve", kind: "Auto" } | ||
| })), | ||
| // `messages.stream()` returns a synchronous emitter, not a promise, so `kind: 'Sync'` is required: | ||
| // `Auto`'s promise wrapper never publishes `end` for a non-thenable return, so the span would never end. | ||
| ...["resources/messages/messages.js", "resources/messages/messages.mjs"].map((filePath) => ({ | ||
| channelName: "messages-stream", | ||
| module: { name: "@anthropic-ai/sdk", versionRange: ">=0.19.2 <1", filePath }, | ||
| functionQuery: { className: "Messages", methodName: "stream", kind: "Sync" } | ||
| })) | ||
| ]; | ||
| const anthropicAiChannels = { | ||
| ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat", | ||
| ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models", | ||
| ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream" | ||
| }; | ||
| export { anthropicAiChannels, anthropicAiConfig }; | ||
| //# sourceMappingURL=anthropic-ai.js.map |
| {"version":3,"file":"anthropic-ai.js","sources":["../../../../src/orchestrion/config/anthropic-ai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const anthropicAiConfig = [\n // One entry each for CJS/ESM\n ...['resources/messages/messages.js', 'resources/messages/messages.mjs'].flatMap(filePath =>\n (['create', 'countTokens'] as const).map(methodName => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName, kind: 'Auto' as const },\n })),\n ),\n ...['resources/completions.js', 'resources/completions.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Completions', methodName: 'create', kind: 'Auto' as const },\n })),\n ...['resources/beta/messages/messages.js', 'resources/beta/messages/messages.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName: 'create', kind: 'Auto' as const },\n })),\n ...['resources/models.js', 'resources/models.mjs'].map(filePath => ({\n channelName: 'models',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Models', methodName: 'retrieve', kind: 'Auto' as const },\n })),\n // `messages.stream()` returns a synchronous emitter, not a promise, so `kind: 'Sync'` is required:\n // `Auto`'s promise wrapper never publishes `end` for a non-thenable return, so the span would never end.\n ...['resources/messages/messages.js', 'resources/messages/messages.mjs'].map(filePath => ({\n channelName: 'messages-stream',\n module: { name: '@anthropic-ai/sdk', versionRange: '>=0.19.2 <1', filePath },\n functionQuery: { className: 'Messages', methodName: 'stream', kind: 'Sync' as const },\n })),\n] satisfies InstrumentationConfig[];\n\nexport const anthropicAiChannels = {\n ANTHROPIC_CHAT: 'orchestrion:@anthropic-ai/sdk:chat',\n ANTHROPIC_MODELS: 'orchestrion:@anthropic-ai/sdk:models',\n ANTHROPIC_MESSAGES_STREAM: 'orchestrion:@anthropic-ai/sdk:messages-stream',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,iBAAA,GAAoB;AAAA;AAAA,EAE/B,GAAG,CAAC,gCAAA,EAAkC,iCAAiC,CAAA,CAAE,OAAA;AAAA,IAAQ,cAC9E,CAAC,QAAA,EAAU,aAAa,CAAA,CAAY,IAAI,CAAA,UAAA,MAAe;AAAA,MACtD,WAAA,EAAa,MAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,MAC3E,eAAe,EAAE,SAAA,EAAW,UAAA,EAAY,UAAA,EAAY,MAAM,MAAA;AAAgB,KAC5E,CAAE;AAAA,GACJ;AAAA,EACA,GAAG,CAAC,0BAAA,EAA4B,2BAA2B,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5E,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,eAAe,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACzF,CAAE,CAAA;AAAA,EACF,GAAG,CAAC,qCAAA,EAAuC,sCAAsC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAClG,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,YAAY,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACtF,CAAE,CAAA;AAAA,EACF,GAAG,CAAC,qBAAA,EAAuB,sBAAsB,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAClE,WAAA,EAAa,QAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,UAAA,EAAY,MAAM,MAAA;AAAgB,GACtF,CAAE,CAAA;AAAA;AAAA;AAAA,EAGF,GAAG,CAAC,gCAAA,EAAkC,iCAAiC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IACxF,WAAA,EAAa,iBAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,mBAAA,EAAqB,YAAA,EAAc,eAAe,QAAA,EAAS;AAAA,IAC3E,eAAe,EAAE,SAAA,EAAW,YAAY,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACtF,CAAE;AACJ;AAEO,MAAM,mBAAA,GAAsB;AAAA,EACjC,cAAA,EAAgB,oCAAA;AAAA,EAChB,gBAAA,EAAkB,sCAAA;AAAA,EAClB,yBAAA,EAA2B;AAC7B;;;;"} |
| const hapiConfig = [ | ||
| // hapi's `route`/`ext` live on an anonymous class (`internals.Server = class {}`), | ||
| // so `{className}` can't match — `{methodName}` targets them in lib/server.js. Both | ||
| // are synchronous void methods, so `Sync` suffices: we only use `start` to swap | ||
| // handlers in `ctx.arguments`. Shape verified across the whole range. | ||
| { | ||
| channelName: "route", | ||
| module: { name: "@hapi/hapi", versionRange: ">=17.0.0 <22.0.0", filePath: "lib/server.js" }, | ||
| functionQuery: { methodName: "route", kind: "Sync" } | ||
| }, | ||
| { | ||
| channelName: "ext", | ||
| module: { name: "@hapi/hapi", versionRange: ">=17.0.0 <22.0.0", filePath: "lib/server.js" }, | ||
| functionQuery: { methodName: "ext", kind: "Sync" } | ||
| } | ||
| ]; | ||
| const hapiChannels = { | ||
| HAPI_ROUTE: "orchestrion:@hapi/hapi:route", | ||
| HAPI_EXT: "orchestrion:@hapi/hapi:ext" | ||
| }; | ||
| export { hapiChannels, hapiConfig }; | ||
| //# sourceMappingURL=hapi.js.map |
| {"version":3,"file":"hapi.js","sources":["../../../../src/orchestrion/config/hapi.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const hapiConfig = [\n // hapi's `route`/`ext` live on an anonymous class (`internals.Server = class {}`),\n // so `{className}` can't match — `{methodName}` targets them in lib/server.js. Both\n // are synchronous void methods, so `Sync` suffices: we only use `start` to swap\n // handlers in `ctx.arguments`. Shape verified across the whole range.\n {\n channelName: 'route',\n module: { name: '@hapi/hapi', versionRange: '>=17.0.0 <22.0.0', filePath: 'lib/server.js' },\n functionQuery: { methodName: 'route', kind: 'Sync' },\n },\n {\n channelName: 'ext',\n module: { name: '@hapi/hapi', versionRange: '>=17.0.0 <22.0.0', filePath: 'lib/server.js' },\n functionQuery: { methodName: 'ext', kind: 'Sync' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const hapiChannels = {\n HAPI_ROUTE: 'orchestrion:@hapi/hapi:route',\n HAPI_EXT: 'orchestrion:@hapi/hapi:ext',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,UAAA,GAAa;AAAA;AAAA;AAAA;AAAA;AAAA,EAKxB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,cAAc,YAAA,EAAc,kBAAA,EAAoB,UAAU,eAAA,EAAgB;AAAA,IAC1F,aAAA,EAAe,EAAE,UAAA,EAAY,OAAA,EAAS,MAAM,MAAA;AAAO,GACrD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,KAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,cAAc,YAAA,EAAc,kBAAA,EAAoB,UAAU,eAAA,EAAgB;AAAA,IAC1F,aAAA,EAAe,EAAE,UAAA,EAAY,KAAA,EAAO,MAAM,MAAA;AAAO;AAErD;AAEO,MAAM,YAAA,GAAe;AAAA,EAC1B,UAAA,EAAY,8BAAA;AAAA,EACZ,QAAA,EAAU;AACZ;;;;"} |
| import { mysqlConfig } from './mysql.js'; | ||
| import { lruMemoizerConfig } from './lru-memoizer.js'; | ||
| import { ioredisConfig } from './ioredis.js'; | ||
| import { openaiConfig } from './openai.js'; | ||
| import { pgConfig } from './pg.js'; | ||
| import { anthropicAiConfig } from './anthropic-ai.js'; | ||
| import { vercelAiConfig } from './vercel-ai.js'; | ||
| import { hapiConfig } from './hapi.js'; | ||
| const SENTRY_INSTRUMENTATIONS = [ | ||
| ...mysqlConfig, | ||
| ...lruMemoizerConfig, | ||
| ...ioredisConfig, | ||
| ...openaiConfig, | ||
| ...pgConfig, | ||
| ...anthropicAiConfig, | ||
| ...vercelAiConfig, | ||
| ...hapiConfig | ||
| ]; | ||
| const INSTRUMENTED_MODULE_NAMES = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map((i) => i.module.name))); | ||
| function withoutInstrumentedExternals(external) { | ||
| if (!external) { | ||
| return void 0; | ||
| } | ||
| return external.filter( | ||
| (entry) => !INSTRUMENTED_MODULE_NAMES.some((name) => entry === name || entry.startsWith(`${name}/`)) | ||
| ); | ||
| } | ||
| export { INSTRUMENTED_MODULE_NAMES, SENTRY_INSTRUMENTATIONS, withoutInstrumentedExternals }; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../../src/orchestrion/config/index.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\nimport { mysqlConfig } from './mysql';\nimport { lruMemoizerConfig } from './lru-memoizer';\nimport { ioredisConfig } from './ioredis';\nimport { openaiConfig } from './openai';\nimport { pgConfig } from './pg';\nimport { anthropicAiConfig } from './anthropic-ai';\nimport { vercelAiConfig } from './vercel-ai';\nimport { hapiConfig } from './hapi';\n\nexport const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[] = [\n ...mysqlConfig,\n ...lruMemoizerConfig,\n ...ioredisConfig,\n ...openaiConfig,\n ...pgConfig,\n ...anthropicAiConfig,\n ...vercelAiConfig,\n ...hapiConfig,\n];\n\n/**\n * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS`\n * (e.g. `['mysql']`).\n *\n * Bundler plugins MUST ensure these are actually bundled rather than\n * externalized: an externalized dependency is resolved from `node_modules` at\n * runtime and never passes through the code transform's `onLoad`, so its\n * diagnostics_channel calls are silently never injected.\n */\nexport const INSTRUMENTED_MODULE_NAMES: string[] = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map(i => i.module.name)));\n\n/**\n * Returns `external` with any instrumented packages removed, so a bundler that\n * uses an \"external\" denylist (esbuild, Bun, Rollup) still bundles — and thus\n * transforms — them. Matches an exact package name (`'mysql'`) or a subpath\n * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined`\n * is returned unchanged.\n *\n * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes\n * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.)\n */\nexport function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined {\n if (!external) {\n return undefined;\n }\n return external.filter(\n entry => !INSTRUMENTED_MODULE_NAMES.some(name => entry === name || entry.startsWith(`${name}/`)),\n );\n}\n"],"names":[],"mappings":";;;;;;;;;AAUO,MAAM,uBAAA,GAAmD;AAAA,EAC9D,GAAG,WAAA;AAAA,EACH,GAAG,iBAAA;AAAA,EACH,GAAG,aAAA;AAAA,EACH,GAAG,YAAA;AAAA,EACH,GAAG,QAAA;AAAA,EACH,GAAG,iBAAA;AAAA,EACH,GAAG,cAAA;AAAA,EACH,GAAG;AACL;AAWO,MAAM,yBAAA,GAAsC,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,uBAAA,CAAwB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,CAAO,IAAI,CAAC,CAAC;AAY/G,SAAS,6BAA6B,QAAA,EAA+D;AAC1G,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAA,KAAA,KAAS,CAAC,yBAAA,CAA0B,IAAA,CAAK,CAAA,IAAA,KAAQ,KAAA,KAAU,IAAA,IAAQ,KAAA,CAAM,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAC;AAAA,GACjG;AACF;;;;"} |
| const ioredisConfig = [ | ||
| // ioredis `<5.11.0` (>=5.11.0 publishes its own `ioredis:*` diagnostics_channel) | ||
| ...["lib/redis.js", "built/redis.js", "built/redis/index.js"].flatMap((filePath) => [ | ||
| { | ||
| channelName: "command", | ||
| module: { name: "ioredis", versionRange: ">=2.0.0 <5.0.0", filePath }, | ||
| functionQuery: { expressionName: "sendCommand", kind: "Async" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "ioredis", versionRange: ">=2.0.0 <5.0.0", filePath }, | ||
| functionQuery: { expressionName: "connect", kind: "Async" } | ||
| } | ||
| ]), | ||
| { | ||
| channelName: "command", | ||
| module: { name: "ioredis", versionRange: ">=5.0.0 <5.11.0", filePath: "built/Redis.js" }, | ||
| functionQuery: { className: "Redis", methodName: "sendCommand", kind: "Async" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "ioredis", versionRange: ">=5.0.0 <5.11.0", filePath: "built/Redis.js" }, | ||
| functionQuery: { className: "Redis", methodName: "connect", kind: "Async" } | ||
| } | ||
| ]; | ||
| const ioredisChannels = { | ||
| IOREDIS_COMMAND: "orchestrion:ioredis:command", | ||
| IOREDIS_CONNECT: "orchestrion:ioredis:connect" | ||
| }; | ||
| export { ioredisChannels, ioredisConfig }; | ||
| //# sourceMappingURL=ioredis.js.map |
| {"version":3,"file":"ioredis.js","sources":["../../../../src/orchestrion/config/ioredis.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const ioredisConfig = [\n // ioredis `<5.11.0` (>=5.11.0 publishes its own `ioredis:*` diagnostics_channel)\n ...['lib/redis.js', 'built/redis.js', 'built/redis/index.js'].flatMap((filePath): InstrumentationConfig[] => [\n {\n channelName: 'command',\n module: { name: 'ioredis', versionRange: '>=2.0.0 <5.0.0', filePath },\n functionQuery: { expressionName: 'sendCommand', kind: 'Async' },\n },\n {\n channelName: 'connect',\n module: { name: 'ioredis', versionRange: '>=2.0.0 <5.0.0', filePath },\n functionQuery: { expressionName: 'connect', kind: 'Async' },\n },\n ]),\n {\n channelName: 'command',\n module: { name: 'ioredis', versionRange: '>=5.0.0 <5.11.0', filePath: 'built/Redis.js' },\n functionQuery: { className: 'Redis', methodName: 'sendCommand', kind: 'Async' },\n },\n {\n channelName: 'connect',\n module: { name: 'ioredis', versionRange: '>=5.0.0 <5.11.0', filePath: 'built/Redis.js' },\n functionQuery: { className: 'Redis', methodName: 'connect', kind: 'Async' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const ioredisChannels = {\n IOREDIS_COMMAND: 'orchestrion:ioredis:command',\n IOREDIS_CONNECT: 'orchestrion:ioredis:connect',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,aAAA,GAAgB;AAAA;AAAA,EAE3B,GAAG,CAAC,cAAA,EAAgB,gBAAA,EAAkB,sBAAsB,CAAA,CAAE,OAAA,CAAQ,CAAC,QAAA,KAAsC;AAAA,IAC3G;AAAA,MACE,WAAA,EAAa,SAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,MACpE,aAAA,EAAe,EAAE,cAAA,EAAgB,aAAA,EAAe,MAAM,OAAA;AAAQ,KAChE;AAAA,IACA;AAAA,MACE,WAAA,EAAa,SAAA;AAAA,MACb,QAAQ,EAAE,IAAA,EAAM,SAAA,EAAW,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,MACpE,aAAA,EAAe,EAAE,cAAA,EAAgB,SAAA,EAAW,MAAM,OAAA;AAAQ;AAC5D,GACD,CAAA;AAAA,EACD;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,iBAAA,EAAmB,UAAU,gBAAA,EAAiB;AAAA,IACvF,eAAe,EAAE,SAAA,EAAW,SAAS,UAAA,EAAY,aAAA,EAAe,MAAM,OAAA;AAAQ,GAChF;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,iBAAA,EAAmB,UAAU,gBAAA,EAAiB;AAAA,IACvF,eAAe,EAAE,SAAA,EAAW,SAAS,UAAA,EAAY,SAAA,EAAW,MAAM,OAAA;AAAQ;AAE9E;AAEO,MAAM,eAAA,GAAkB;AAAA,EAC7B,eAAA,EAAiB,6BAAA;AAAA,EACjB,eAAA,EAAiB;AACnB;;;;"} |
| const lruMemoizerConfig = [ | ||
| { | ||
| channelName: "load", | ||
| // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0 | ||
| module: { name: "lru-memoizer", versionRange: ">=2.1.0 <4", filePath: "lib/async.js" }, | ||
| functionQuery: { functionName: "memoizedFunction", kind: "Callback" } | ||
| } | ||
| ]; | ||
| const lruMemoizerChannels = { | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| }; | ||
| export { lruMemoizerChannels, lruMemoizerConfig }; | ||
| //# sourceMappingURL=lru-memoizer.js.map |
| {"version":3,"file":"lru-memoizer.js","sources":["../../../../src/orchestrion/config/lru-memoizer.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const lruMemoizerConfig = [\n {\n channelName: 'load',\n // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0\n module: { name: 'lru-memoizer', versionRange: '>=2.1.0 <4', filePath: 'lib/async.js' },\n functionQuery: { functionName: 'memoizedFunction', kind: 'Callback' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const lruMemoizerChannels = {\n LRU_MEMOIZER_LOAD: 'orchestrion:lru-memoizer:load',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,iBAAA,GAAoB;AAAA,EAC/B;AAAA,IACE,WAAA,EAAa,MAAA;AAAA;AAAA,IAEb,QAAQ,EAAE,IAAA,EAAM,gBAAgB,YAAA,EAAc,YAAA,EAAc,UAAU,cAAA,EAAe;AAAA,IACrF,aAAA,EAAe,EAAE,YAAA,EAAc,kBAAA,EAAoB,MAAM,UAAA;AAAW;AAExE;AAEO,MAAM,mBAAA,GAAsB;AAAA,EACjC,iBAAA,EAAmB;AACrB;;;;"} |
| const mysqlConfig = [ | ||
| { | ||
| channelName: "query", | ||
| module: { name: "mysql", versionRange: ">=2.0.0 <3", filePath: "lib/Connection.js" }, | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| } | ||
| ]; | ||
| const mysqlChannels = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query" | ||
| }; | ||
| export { mysqlChannels, mysqlConfig }; | ||
| //# sourceMappingURL=mysql.js.map |
| {"version":3,"file":"mysql.js","sources":["../../../../src/orchestrion/config/mysql.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const mysqlConfig = [\n {\n channelName: 'query',\n module: { name: 'mysql', versionRange: '>=2.0.0 <3', filePath: 'lib/Connection.js' },\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const mysqlChannels = {\n MYSQL_QUERY: 'orchestrion:mysql:query',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,WAAA,GAAc;AAAA,EACzB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,SAAS,YAAA,EAAc,YAAA,EAAc,UAAU,mBAAA,EAAoB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO;AAE3D;AAEO,MAAM,aAAA,GAAgB;AAAA,EAC3B,WAAA,EAAa;AACf;;;;"} |
| const openaiConfig = [ | ||
| // OpenAI chat completions. `Completions.create` returns a thenable `APIPromise` with no callback arg, | ||
| // so `kind: 'Auto'` resolves to `wrapPromise`. openai ships dual CJS/ESM and the matcher compares | ||
| // `filePath` exactly, hence one entry per built file (`.js` for `require`, `.mjs` for `import`). | ||
| ...["resources/chat/completions/completions.js", "resources/chat/completions/completions.mjs"].map((filePath) => ({ | ||
| channelName: "chat", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Completions", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI responses API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/responses/responses.js", "resources/responses/responses.mjs"].map((filePath) => ({ | ||
| channelName: "responses", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Responses", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI embeddings API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/embeddings.js", "resources/embeddings.mjs"].map((filePath) => ({ | ||
| channelName: "embeddings", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Embeddings", methodName: "create", kind: "Auto" } | ||
| })), | ||
| // OpenAI conversations API — same `create(body, options)` shape as chat completions. | ||
| ...["resources/conversations/conversations.js", "resources/conversations/conversations.mjs"].map((filePath) => ({ | ||
| channelName: "conversations", | ||
| module: { name: "openai", versionRange: ">=4.0.0 <7", filePath }, | ||
| functionQuery: { className: "Conversations", methodName: "create", kind: "Auto" } | ||
| })) | ||
| ]; | ||
| const openaiChannels = { | ||
| OPENAI_CHAT: "orchestrion:openai:chat", | ||
| OPENAI_RESPONSES: "orchestrion:openai:responses", | ||
| OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings", | ||
| OPENAI_CONVERSATIONS: "orchestrion:openai:conversations" | ||
| }; | ||
| export { openaiChannels, openaiConfig }; | ||
| //# sourceMappingURL=openai.js.map |
| {"version":3,"file":"openai.js","sources":["../../../../src/orchestrion/config/openai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const openaiConfig = [\n // OpenAI chat completions. `Completions.create` returns a thenable `APIPromise` with no callback arg,\n // so `kind: 'Auto'` resolves to `wrapPromise`. openai ships dual CJS/ESM and the matcher compares\n // `filePath` exactly, hence one entry per built file (`.js` for `require`, `.mjs` for `import`).\n ...['resources/chat/completions/completions.js', 'resources/chat/completions/completions.mjs'].map(filePath => ({\n channelName: 'chat',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Completions', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI responses API — same `create(body, options)` shape as chat completions.\n ...['resources/responses/responses.js', 'resources/responses/responses.mjs'].map(filePath => ({\n channelName: 'responses',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Responses', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI embeddings API — same `create(body, options)` shape as chat completions.\n ...['resources/embeddings.js', 'resources/embeddings.mjs'].map(filePath => ({\n channelName: 'embeddings',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Embeddings', methodName: 'create', kind: 'Auto' as const },\n })),\n // OpenAI conversations API — same `create(body, options)` shape as chat completions.\n ...['resources/conversations/conversations.js', 'resources/conversations/conversations.mjs'].map(filePath => ({\n channelName: 'conversations',\n module: { name: 'openai', versionRange: '>=4.0.0 <7', filePath },\n functionQuery: { className: 'Conversations', methodName: 'create', kind: 'Auto' as const },\n })),\n] satisfies InstrumentationConfig[];\n\nexport const openaiChannels = {\n OPENAI_CHAT: 'orchestrion:openai:chat',\n OPENAI_RESPONSES: 'orchestrion:openai:responses',\n OPENAI_EMBEDDINGS: 'orchestrion:openai:embeddings',\n OPENAI_CONVERSATIONS: 'orchestrion:openai:conversations',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,YAAA,GAAe;AAAA;AAAA;AAAA;AAAA,EAI1B,GAAG,CAAC,2CAAA,EAA6C,4CAA4C,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC9G,WAAA,EAAa,MAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,eAAe,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACzF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,kCAAA,EAAoC,mCAAmC,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5F,WAAA,EAAa,WAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,aAAa,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACvF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,yBAAA,EAA2B,0BAA0B,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC1E,WAAA,EAAa,YAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,cAAc,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GACxF,CAAE,CAAA;AAAA;AAAA,EAEF,GAAG,CAAC,0CAAA,EAA4C,2CAA2C,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC5G,WAAA,EAAa,eAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,QAAA,EAAU,YAAA,EAAc,cAAc,QAAA,EAAS;AAAA,IAC/D,eAAe,EAAE,SAAA,EAAW,iBAAiB,UAAA,EAAY,QAAA,EAAU,MAAM,MAAA;AAAgB,GAC3F,CAAE;AACJ;AAEO,MAAM,cAAA,GAAiB;AAAA,EAC5B,WAAA,EAAa,yBAAA;AAAA,EACb,gBAAA,EAAkB,8BAAA;AAAA,EAClB,iBAAA,EAAmB,+BAAA;AAAA,EACnB,oBAAA,EAAsB;AACxB;;;;"} |
| const pgConfig = [ | ||
| // `pg` (node-postgres). | ||
| // instruments `Client.prototype.query`/`connect` (both the JS and native | ||
| // clients) plus `pg-pool`'s `Pool.prototype.connect`. | ||
| // `Auto` covers the callback, promise, and streamable-`Submittable` | ||
| // call shapes (like mysql). | ||
| // `pg/lib/client.js` is `class Client { query() {...} connect() {...} }`, | ||
| // so `className`+`methodName` matches directly. | ||
| { | ||
| channelName: "query", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/client.js" }, | ||
| functionQuery: { className: "Client", methodName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/client.js" }, | ||
| functionQuery: { className: "Client", methodName: "connect", kind: "Auto" } | ||
| }, | ||
| // The native client (`pg/lib/native/client.js`) is a constructor function, | ||
| // not a class. | ||
| // `Client.prototype.query = function (config, values, callback) {...}` | ||
| // so it needs `expressionName` (the mysql shape), publishing to the SAME | ||
| // `orchestrion:pg:query`/`:connect` channels as the JS client. | ||
| { | ||
| channelName: "query", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/native/client.js" }, | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg", versionRange: ">=8.0.3 <9", filePath: "lib/native/client.js" }, | ||
| functionQuery: { expressionName: "connect", kind: "Auto" } | ||
| }, | ||
| // `pg-pool` is `class Pool extends EventEmitter { connect(cb) {...} }`. | ||
| { | ||
| channelName: "connect", | ||
| module: { name: "pg-pool", versionRange: ">=2.0.0 <4", filePath: "index.js" }, | ||
| functionQuery: { className: "Pool", methodName: "connect", kind: "Auto" } | ||
| } | ||
| ]; | ||
| const pgChannels = { | ||
| PG_QUERY: "orchestrion:pg:query", | ||
| PG_CONNECT: "orchestrion:pg:connect", | ||
| PGPOOL_CONNECT: "orchestrion:pg-pool:connect" | ||
| }; | ||
| export { pgChannels, pgConfig }; | ||
| //# sourceMappingURL=pg.js.map |
| {"version":3,"file":"pg.js","sources":["../../../../src/orchestrion/config/pg.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const pgConfig = [\n // `pg` (node-postgres).\n // instruments `Client.prototype.query`/`connect` (both the JS and native\n // clients) plus `pg-pool`'s `Pool.prototype.connect`.\n // `Auto` covers the callback, promise, and streamable-`Submittable`\n // call shapes (like mysql).\n // `pg/lib/client.js` is `class Client { query() {...} connect() {...} }`,\n // so `className`+`methodName` matches directly.\n {\n channelName: 'query',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/client.js' },\n functionQuery: { className: 'Client', methodName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'connect',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/client.js' },\n functionQuery: { className: 'Client', methodName: 'connect', kind: 'Auto' },\n },\n // The native client (`pg/lib/native/client.js`) is a constructor function,\n // not a class.\n // `Client.prototype.query = function (config, values, callback) {...}`\n // so it needs `expressionName` (the mysql shape), publishing to the SAME\n // `orchestrion:pg:query`/`:connect` channels as the JS client.\n {\n channelName: 'query',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/native/client.js' },\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'connect',\n module: { name: 'pg', versionRange: '>=8.0.3 <9', filePath: 'lib/native/client.js' },\n functionQuery: { expressionName: 'connect', kind: 'Auto' },\n },\n // `pg-pool` is `class Pool extends EventEmitter { connect(cb) {...} }`.\n {\n channelName: 'connect',\n module: { name: 'pg-pool', versionRange: '>=2.0.0 <4', filePath: 'index.js' },\n functionQuery: { className: 'Pool', methodName: 'connect', kind: 'Auto' },\n },\n] satisfies InstrumentationConfig[];\n\nexport const pgChannels = {\n PG_QUERY: 'orchestrion:pg:query',\n PG_CONNECT: 'orchestrion:pg:connect',\n PGPOOL_CONNECT: 'orchestrion:pg-pool:connect',\n} as const;\n"],"names":[],"mappings":"AAEO,MAAM,QAAA,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQtB;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,eAAA,EAAgB;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,OAAA,EAAS,MAAM,MAAA;AAAO,GAC1E;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,eAAA,EAAgB;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,UAAU,UAAA,EAAY,SAAA,EAAW,MAAM,MAAA;AAAO,GAC5E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,sBAAA,EAAuB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO,GACzD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,MAAM,YAAA,EAAc,YAAA,EAAc,UAAU,sBAAA,EAAuB;AAAA,IACnF,aAAA,EAAe,EAAE,cAAA,EAAgB,SAAA,EAAW,MAAM,MAAA;AAAO,GAC3D;AAAA;AAAA,EAEA;AAAA,IACE,WAAA,EAAa,SAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,WAAW,YAAA,EAAc,YAAA,EAAc,UAAU,UAAA,EAAW;AAAA,IAC5E,eAAe,EAAE,SAAA,EAAW,QAAQ,UAAA,EAAY,SAAA,EAAW,MAAM,MAAA;AAAO;AAE5E;AAEO,MAAM,UAAA,GAAa;AAAA,EACxB,QAAA,EAAU,sBAAA;AAAA,EACV,UAAA,EAAY,wBAAA;AAAA,EACZ,cAAA,EAAgB;AAClB;;;;"} |
| const vercelAiConfig = [ | ||
| // Vercel AI v6: mirror the v7 native `ai:telemetry` channel by injecting | ||
| // channels into the top-level entry points. `resolveLanguageModel` is wrapped | ||
| // not to span it, but so the subscriber can monkey-patch `doGenerate`/ | ||
| // `doStream` on the returned model (the only way to span the model call, | ||
| // which is an inline call with no injectable definition in `ai`). | ||
| // `streamText` returns its result synchronously (streaming is lazy), so it's | ||
| // `Sync`; the subscriber binds the span via `bindTracingChannelToSpan`, which | ||
| // ends it when the (synchronous) call returns. | ||
| ...vercelAiV6Entries("generateText", "generateText", "Async"), | ||
| ...vercelAiV6Entries("streamText", "streamText", "Sync"), | ||
| ...vercelAiV6Entries("embed", "embed", "Async"), | ||
| ...vercelAiV6Entries("embedMany", "embedMany", "Async"), | ||
| ...vercelAiV6Entries("executeToolCall", "executeToolCall", "Async"), | ||
| ...vercelAiV6Entries("resolveLanguageModel", "resolveLanguageModel", "Sync") | ||
| ]; | ||
| const vercelAiChannels = { | ||
| // Vercel AI (`ai`) v6: orchestrion injects these so the same channel-based | ||
| // integration that consumes `ai`'s native `ai:telemetry` channel (v7) can | ||
| // also instrument v6. Each maps to a top-level function in `ai`'s bundle. | ||
| VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText", | ||
| VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText", | ||
| VERCEL_AI_EMBED: "orchestrion:ai:embed", | ||
| VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany", | ||
| VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall", | ||
| // `resolveLanguageModel` is the single chokepoint every model call flows | ||
| // through; we wrap it to monkey-patch `doGenerate`/`doStream` on the returned | ||
| // model (the model-call site itself is an inline call with no injectable | ||
| // definition). | ||
| VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel" | ||
| }; | ||
| function vercelAiV6Entries(channelName, functionName, kind) { | ||
| return ["dist/index.js", "dist/index.mjs"].map((filePath) => ({ | ||
| channelName, | ||
| module: { name: "ai", versionRange: ">=6.0.0 <7.0.0", filePath }, | ||
| functionQuery: { functionName, kind } | ||
| })); | ||
| } | ||
| export { vercelAiChannels, vercelAiConfig }; | ||
| //# sourceMappingURL=vercel-ai.js.map |
| {"version":3,"file":"vercel-ai.js","sources":["../../../../src/orchestrion/config/vercel-ai.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\nexport const vercelAiConfig = [\n // Vercel AI v6: mirror the v7 native `ai:telemetry` channel by injecting\n // channels into the top-level entry points. `resolveLanguageModel` is wrapped\n // not to span it, but so the subscriber can monkey-patch `doGenerate`/\n // `doStream` on the returned model (the only way to span the model call,\n // which is an inline call with no injectable definition in `ai`).\n // `streamText` returns its result synchronously (streaming is lazy), so it's\n // `Sync`; the subscriber binds the span via `bindTracingChannelToSpan`, which\n // ends it when the (synchronous) call returns.\n ...vercelAiV6Entries('generateText', 'generateText', 'Async'),\n ...vercelAiV6Entries('streamText', 'streamText', 'Sync'),\n ...vercelAiV6Entries('embed', 'embed', 'Async'),\n ...vercelAiV6Entries('embedMany', 'embedMany', 'Async'),\n ...vercelAiV6Entries('executeToolCall', 'executeToolCall', 'Async'),\n ...vercelAiV6Entries('resolveLanguageModel', 'resolveLanguageModel', 'Sync'),\n] satisfies InstrumentationConfig[];\n\nexport const vercelAiChannels = {\n // Vercel AI (`ai`) v6: orchestrion injects these so the same channel-based\n // integration that consumes `ai`'s native `ai:telemetry` channel (v7) can\n // also instrument v6. Each maps to a top-level function in `ai`'s bundle.\n VERCEL_AI_GENERATE_TEXT: 'orchestrion:ai:generateText',\n VERCEL_AI_STREAM_TEXT: 'orchestrion:ai:streamText',\n VERCEL_AI_EMBED: 'orchestrion:ai:embed',\n VERCEL_AI_EMBED_MANY: 'orchestrion:ai:embedMany',\n VERCEL_AI_EXECUTE_TOOL_CALL: 'orchestrion:ai:executeToolCall',\n // `resolveLanguageModel` is the single chokepoint every model call flows\n // through; we wrap it to monkey-patch `doGenerate`/`doStream` on the returned\n // model (the model-call site itself is an inline call with no injectable\n // definition).\n VERCEL_AI_RESOLVE_LANGUAGE_MODEL: 'orchestrion:ai:resolveLanguageModel',\n} as const;\n\n/**\n * The central list of channel injections orchestrion should perform.\n *\n * This module has NO side effects — it's the only thing both the runtime hook\n * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …)\n * import from. Adding a new instrumented method is one entry here plus one\n * subscriber in `integrations/<lib>/tracing-channel.ts`.\n *\n * `channelName` here is the unprefixed suffix; the actual diagnostics_channel\n * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`).\n */\n/**\n * `ai` ships a single bundled entry per module system, so each instrumented\n * function needs one config entry per file (the app loads whichever matches its\n * module system). This expands a single target into both.\n */\nfunction vercelAiV6Entries(channelName: string, functionName: string, kind: 'Async' | 'Sync'): InstrumentationConfig[] {\n return ['dist/index.js', 'dist/index.mjs'].map(filePath => ({\n channelName,\n module: { name: 'ai', versionRange: '>=6.0.0 <7.0.0', filePath },\n functionQuery: { functionName, kind },\n }));\n}\n"],"names":[],"mappings":"AAEO,MAAM,cAAA,GAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAS5B,GAAG,iBAAA,CAAkB,cAAA,EAAgB,cAAA,EAAgB,OAAO,CAAA;AAAA,EAC5D,GAAG,iBAAA,CAAkB,YAAA,EAAc,YAAA,EAAc,MAAM,CAAA;AAAA,EACvD,GAAG,iBAAA,CAAkB,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA;AAAA,EAC9C,GAAG,iBAAA,CAAkB,WAAA,EAAa,WAAA,EAAa,OAAO,CAAA;AAAA,EACtD,GAAG,iBAAA,CAAkB,iBAAA,EAAmB,iBAAA,EAAmB,OAAO,CAAA;AAAA,EAClE,GAAG,iBAAA,CAAkB,sBAAA,EAAwB,sBAAA,EAAwB,MAAM;AAC7E;AAEO,MAAM,gBAAA,GAAmB;AAAA;AAAA;AAAA;AAAA,EAI9B,uBAAA,EAAyB,6BAAA;AAAA,EACzB,qBAAA,EAAuB,2BAAA;AAAA,EACvB,eAAA,EAAiB,sBAAA;AAAA,EACjB,oBAAA,EAAsB,0BAAA;AAAA,EACtB,2BAAA,EAA6B,gCAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAK7B,gCAAA,EAAkC;AACpC;AAkBA,SAAS,iBAAA,CAAkB,WAAA,EAAqB,YAAA,EAAsB,IAAA,EAAiD;AACrH,EAAA,OAAO,CAAC,eAAA,EAAiB,gBAAgB,CAAA,CAAE,IAAI,CAAA,QAAA,MAAa;AAAA,IAC1D,WAAA;AAAA,IACA,QAAQ,EAAE,IAAA,EAAM,IAAA,EAAM,YAAA,EAAc,kBAAkB,QAAA,EAAS;AAAA,IAC/D,aAAA,EAAe,EAAE,YAAA,EAAc,IAAA;AAAK,GACtC,CAAE,CAAA;AACJ;;;;"} |
| const serializationSubsets = [ | ||
| { | ||
| regex: /^ECHO/i, | ||
| args: 0 | ||
| }, | ||
| { | ||
| regex: /^(LPUSH|MSET|PFA|PUBLISH|RPUSH|SADD|SET|SPUBLISH|XADD|ZADD)/i, | ||
| args: 1 | ||
| }, | ||
| { | ||
| regex: /^(HSET|HMSET|LSET|LINSERT)/i, | ||
| args: 2 | ||
| }, | ||
| { | ||
| regex: /^(ACL|BIT|B[LRZ]|CLIENT|CLUSTER|CONFIG|COMMAND|DECR|DEL|EVAL|EX|FUNCTION|GEO|GET|HINCR|HMGET|HSCAN|INCR|L[TRLM]|MEMORY|P[EFISTU]|RPOP|S[CDIMORSU]|XACK|X[CDGILPRT]|Z[CDILMPRS])/i, | ||
| args: -1 | ||
| } | ||
| ]; | ||
| const defaultDbStatementSerializer = (cmdName, cmdArgs) => { | ||
| if (Array.isArray(cmdArgs) && cmdArgs.length) { | ||
| const nArgsToSerialize = serializationSubsets.find(({ regex }) => regex.test(cmdName))?.args ?? 0; | ||
| const argsToSerialize = nArgsToSerialize >= 0 ? cmdArgs.slice(0, nArgsToSerialize) : cmdArgs.slice(); | ||
| if (cmdArgs.length > argsToSerialize.length) { | ||
| argsToSerialize.push(`[${cmdArgs.length - nArgsToSerialize} other arguments]`); | ||
| } | ||
| return `${cmdName} ${argsToSerialize.join(" ")}`; | ||
| } | ||
| return cmdName; | ||
| }; | ||
| export { defaultDbStatementSerializer }; | ||
| //# sourceMappingURL=redis-statement-serializer.js.map |
| {"version":3,"file":"redis-statement-serializer.js","sources":["../../../src/redis/redis-statement-serializer.ts"],"sourcesContent":["/*\n * Copyright The OpenTelemetry Authors\n * SPDX-License-Identifier: Apache-2.0\n *\n * NOTICE from the Sentry authors:\n * - Vendored from: https://github.com/open-telemetry/opentelemetry-js-contrib/tree/instrumentation-redis-v0.62.0/packages/redis-common\n * - Upstream version: @opentelemetry/redis-common@0.38.2\n *\n * Single canonical copy, shared by the orchestrion ioredis subscriber here and\n * the node SDK's vendored redis/ioredis instrumentations (which re-export it via\n * `packages/node/src/integrations/tracing/redis/vendored/redis-common.ts`).\n */\n/* eslint-disable -- vendored @opentelemetry/redis-common */\n\n/**\n * List of regexes and the number of arguments that should be serialized for matching commands.\n * For example, HSET should serialize which key and field it's operating on, but not its value.\n * Setting the subset to -1 will serialize all arguments.\n * Commands without a match will have their first argument serialized.\n *\n * Refer to https://redis.io/commands/ for the full list.\n */\nconst serializationSubsets = [\n {\n regex: /^ECHO/i,\n args: 0,\n },\n {\n regex: /^(LPUSH|MSET|PFA|PUBLISH|RPUSH|SADD|SET|SPUBLISH|XADD|ZADD)/i,\n args: 1,\n },\n {\n regex: /^(HSET|HMSET|LSET|LINSERT)/i,\n args: 2,\n },\n {\n regex:\n /^(ACL|BIT|B[LRZ]|CLIENT|CLUSTER|CONFIG|COMMAND|DECR|DEL|EVAL|EX|FUNCTION|GEO|GET|HINCR|HMGET|HSCAN|INCR|L[TRLM]|MEMORY|P[EFISTU]|RPOP|S[CDIMORSU]|XACK|X[CDGILPRT]|Z[CDILMPRS])/i,\n args: -1,\n },\n];\n\n/**\n * Given the redis command name and arguments, return a combination of the\n * command name + the allowed arguments according to `serializationSubsets`.\n */\nexport const defaultDbStatementSerializer = (\n cmdName: string,\n cmdArgs: Array<string | Buffer | number | unknown[]>,\n): string => {\n if (Array.isArray(cmdArgs) && cmdArgs.length) {\n const nArgsToSerialize = serializationSubsets.find(({ regex }) => regex.test(cmdName))?.args ?? 0;\n const argsToSerialize: Array<string | Buffer | number | unknown[]> =\n nArgsToSerialize >= 0 ? cmdArgs.slice(0, nArgsToSerialize) : cmdArgs.slice();\n if (cmdArgs.length > argsToSerialize.length) {\n argsToSerialize.push(`[${cmdArgs.length - nArgsToSerialize} other arguments]`);\n }\n return `${cmdName} ${argsToSerialize.join(' ')}`;\n }\n return cmdName;\n};\n"],"names":[],"mappings":"AAsBA,MAAM,oBAAA,GAAuB;AAAA,EAC3B;AAAA,IACE,KAAA,EAAO,QAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,8DAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EAAO,6BAAA;AAAA,IACP,IAAA,EAAM;AAAA,GACR;AAAA,EACA;AAAA,IACE,KAAA,EACE,kLAAA;AAAA,IACF,IAAA,EAAM;AAAA;AAEV,CAAA;AAMO,MAAM,4BAAA,GAA+B,CAC1C,OAAA,EACA,OAAA,KACW;AACX,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,OAAO,CAAA,IAAK,QAAQ,MAAA,EAAQ;AAC5C,IAAA,MAAM,gBAAA,GAAmB,oBAAA,CAAqB,IAAA,CAAK,CAAC,EAAE,KAAA,EAAM,KAAM,KAAA,CAAM,IAAA,CAAK,OAAO,CAAC,CAAA,EAAG,IAAA,IAAQ,CAAA;AAChG,IAAA,MAAM,eAAA,GACJ,oBAAoB,CAAA,GAAI,OAAA,CAAQ,MAAM,CAAA,EAAG,gBAAgB,CAAA,GAAI,OAAA,CAAQ,KAAA,EAAM;AAC7E,IAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,eAAA,CAAgB,MAAA,EAAQ;AAC3C,MAAA,eAAA,CAAgB,IAAA,CAAK,CAAA,CAAA,EAAI,OAAA,CAAQ,MAAA,GAAS,gBAAgB,CAAA,iBAAA,CAAmB,CAAA;AAAA,IAC/E;AACA,IAAA,OAAO,GAAG,OAAO,CAAA,CAAA,EAAI,eAAA,CAAgB,IAAA,CAAK,GAAG,CAAC,CAAA,CAAA;AAAA,EAChD;AACA,EAAA,OAAO,OAAA;AACT;;;;"} |
| import { debug, withActiveSpan, getActiveSpan, SPAN_STATUS_ERROR } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../debug-build.js'; | ||
| import { CHANNELS } from '../orchestrion/channels.js'; | ||
| import { bindTracingChannelToSpan } from '../tracing-channel.js'; | ||
| import { createSpanFromMessage, enrichSpanOnEnd, clearOperationCallId, clearOperationId } from './vercel-ai-dc-subscriber.js'; | ||
| const PATCHED = /* @__PURE__ */ Symbol("SentryVercelAiModelPatched"); | ||
| let callIdCounter = 0; | ||
| function nextCallId() { | ||
| return `v6-${++callIdCounter}`; | ||
| } | ||
| const messages = /* @__PURE__ */ new WeakMap(); | ||
| const operationSpans = /* @__PURE__ */ new WeakSet(); | ||
| const callIdBySpan = /* @__PURE__ */ new WeakMap(); | ||
| const recordingBySpan = /* @__PURE__ */ new WeakMap(); | ||
| const suppressedTelemetry = /* @__PURE__ */ new WeakSet(); | ||
| let subscribed = false; | ||
| function subscribeVercelAiOrchestrionChannels(tracingChannel, options = {}) { | ||
| if (subscribed) { | ||
| return; | ||
| } | ||
| subscribed = true; | ||
| try { | ||
| bindOperation(tracingChannel, CHANNELS.VERCEL_AI_GENERATE_TEXT, buildTextMessage("generateText"), options); | ||
| bindOperation(tracingChannel, CHANNELS.VERCEL_AI_STREAM_TEXT, buildTextMessage("streamText"), options); | ||
| bindOperation( | ||
| tracingChannel, | ||
| CHANNELS.VERCEL_AI_EMBED, | ||
| (callOptions, telemetry) => ({ | ||
| type: "embed", | ||
| event: { | ||
| callId: nextCallId(), | ||
| ...modelFields(callOptions.model), | ||
| maxRetries: callOptions.maxRetries, | ||
| value: callOptions.value, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| bindOperation( | ||
| tracingChannel, | ||
| CHANNELS.VERCEL_AI_EMBED_MANY, | ||
| // `embedMany` takes a `values` array (vs `embed`'s single `value`); the shared core reads it as the | ||
| // embeddings input, matching the OTel path's batch `ai.embedMany` span. | ||
| (callOptions, telemetry) => ({ | ||
| type: "embedMany", | ||
| event: { | ||
| callId: nextCallId(), | ||
| ...modelFields(callOptions.model), | ||
| maxRetries: callOptions.maxRetries, | ||
| values: callOptions.values, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| bindOperation( | ||
| tracingChannel, | ||
| CHANNELS.VERCEL_AI_EXECUTE_TOOL_CALL, | ||
| (callOptions, telemetry) => ({ | ||
| type: "executeTool", | ||
| // v6 carries the tool definitions on the executeToolCall args (a record keyed by name); | ||
| // the shared core reads the matching tool's `description` for the span. | ||
| event: { | ||
| callId: nextCallId(), | ||
| toolCall: callOptions.toolCall, | ||
| tools: callOptions.tools, | ||
| ...recording(telemetry) | ||
| } | ||
| }), | ||
| options | ||
| ); | ||
| subscribeResolveLanguageModel(tracingChannel, CHANNELS.VERCEL_AI_RESOLVE_LANGUAGE_MODEL, options); | ||
| } catch { | ||
| DEBUG_BUILD && debug.log("Vercel AI orchestrion channel subscription failed."); | ||
| } | ||
| } | ||
| function bindOperation(tracingChannel, channelName, build, options) { | ||
| const channel = tracingChannel(channelName); | ||
| const buildOperationSpan = (data) => { | ||
| const callOptions = isRecord(data.arguments[0]) ? data.arguments[0] : {}; | ||
| const telemetry = isRecord(callOptions.experimental_telemetry) ? callOptions.experimental_telemetry : {}; | ||
| if (telemetry.isEnabled === false && !suppressedTelemetry.has(telemetry)) { | ||
| return void 0; | ||
| } | ||
| const message = build(callOptions, telemetry); | ||
| suppressNativeTelemetry(callOptions, telemetry); | ||
| const span = createSpanFromMessage(message, options); | ||
| if (span) { | ||
| messages.set(data, message); | ||
| operationSpans.add(span); | ||
| const callId = asString(message.event.callId); | ||
| if (callId) { | ||
| callIdBySpan.set(span, callId); | ||
| } | ||
| recordingBySpan.set(span, recording(telemetry)); | ||
| } | ||
| return span; | ||
| }; | ||
| bindTracingChannelToSpan( | ||
| channel, | ||
| (data) => buildOperationSpan(data), | ||
| { | ||
| beforeSpanEnd: (span, data) => { | ||
| const message = messages.get(data); | ||
| if (!message) { | ||
| return; | ||
| } | ||
| if (!("error" in data)) { | ||
| message.result = message.type === "executeTool" ? { output: data.result } : data.result; | ||
| enrichSpanOnEnd(span, message, options); | ||
| } | ||
| if (message.type !== "streamText") { | ||
| clearOperationId(message); | ||
| } | ||
| messages.delete(data); | ||
| } | ||
| } | ||
| ); | ||
| } | ||
| function suppressNativeTelemetry(callOptions, telemetry) { | ||
| if (telemetry.isEnabled !== true) { | ||
| return; | ||
| } | ||
| const suppressed = { ...telemetry, isEnabled: false }; | ||
| suppressedTelemetry.add(suppressed); | ||
| callOptions.experimental_telemetry = suppressed; | ||
| } | ||
| function subscribeResolveLanguageModel(tracingChannel, channelName, options) { | ||
| tracingChannel(channelName).subscribe({ | ||
| end(rawCtx) { | ||
| const ctx = rawCtx; | ||
| if (!isRecord(ctx.result)) { | ||
| return; | ||
| } | ||
| const model = ctx.result; | ||
| if (!model[PATCHED]) { | ||
| model[PATCHED] = true; | ||
| patchModelMethod(model, "doGenerate", options); | ||
| patchModelMethod(model, "doStream", options); | ||
| } | ||
| }, | ||
| start() { | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd() { | ||
| }, | ||
| error() { | ||
| } | ||
| }); | ||
| } | ||
| function resolveModelCallParent() { | ||
| const active = getActiveSpan(); | ||
| return active && operationSpans.has(active) ? active : void 0; | ||
| } | ||
| function patchModelMethod(model, method, options) { | ||
| const original = model[method]; | ||
| if (typeof original !== "function") { | ||
| return; | ||
| } | ||
| model[method] = function(...args) { | ||
| const parent = resolveModelCallParent(); | ||
| if (!parent) { | ||
| return Promise.resolve(original.apply(this, args)); | ||
| } | ||
| const callArgs = isRecord(args[0]) ? args[0] : {}; | ||
| const callId = callIdBySpan.get(parent); | ||
| const message = { | ||
| type: "languageModelCall", | ||
| event: { | ||
| callId, | ||
| provider: model.provider, | ||
| modelId: model.modelId, | ||
| tools: callArgs.tools, | ||
| messages: callArgs.prompt, | ||
| // Inherit the enclosing operation's per-call recording flags so inputs/tools/outputs are recorded on | ||
| // the model-call span whenever they are on the parent `invoke_agent` span. | ||
| ...recordingBySpan.get(parent) | ||
| } | ||
| }; | ||
| const span = withActiveSpan(parent, () => createSpanFromMessage(message, options)); | ||
| if (!span) { | ||
| return Promise.resolve(original.apply(this, args)); | ||
| } | ||
| const clearStreamCallId = () => { | ||
| if (method === "doStream" && callId) { | ||
| clearOperationCallId(callId); | ||
| } | ||
| }; | ||
| const failSpan = (error) => { | ||
| span.setStatus({ code: SPAN_STATUS_ERROR, message: error instanceof Error ? error.message : "unknown_error" }); | ||
| span.end(); | ||
| clearStreamCallId(); | ||
| throw error; | ||
| }; | ||
| try { | ||
| const result = Promise.resolve(original.apply(this, args)); | ||
| return result.then((value) => { | ||
| message.result = value; | ||
| enrichSpanOnEnd(span, message, options); | ||
| span.end(); | ||
| clearStreamCallId(); | ||
| return value; | ||
| }, failSpan); | ||
| } catch (error) { | ||
| return failSpan(error); | ||
| } | ||
| }; | ||
| } | ||
| function buildTextMessage(type) { | ||
| return (options, telemetry) => ({ | ||
| type, | ||
| event: { | ||
| callId: nextCallId(), | ||
| operationId: `ai.${type}`, | ||
| functionId: asString(telemetry.functionId), | ||
| ...modelFields(options.model), | ||
| maxRetries: options.maxRetries, | ||
| // Normalize to the message-array shape the shared core (and v7's channel) expects: a bare string | ||
| // `prompt` becomes a single user message, matching the SDK's own normalization. | ||
| messages: normalizePromptMessages(options), | ||
| ...recording(telemetry) | ||
| } | ||
| }); | ||
| } | ||
| function normalizePromptMessages(options) { | ||
| if (Array.isArray(options.messages)) { | ||
| return options.messages; | ||
| } | ||
| if (typeof options.prompt === "string") { | ||
| return [{ role: "user", content: options.prompt }]; | ||
| } | ||
| return options.messages ?? options.prompt; | ||
| } | ||
| function recording(telemetry) { | ||
| return { recordInputs: telemetry.recordInputs, recordOutputs: telemetry.recordOutputs }; | ||
| } | ||
| function modelFields(model) { | ||
| return { provider: modelField(model, "provider"), modelId: modelField(model, "modelId") }; | ||
| } | ||
| function modelField(model, field) { | ||
| return isRecord(model) ? asString(model[field]) : void 0; | ||
| } | ||
| function asString(value) { | ||
| return typeof value === "string" ? value : void 0; | ||
| } | ||
| function isRecord(value) { | ||
| return typeof value === "object" && value !== null; | ||
| } | ||
| export { subscribeVercelAiOrchestrionChannels }; | ||
| //# sourceMappingURL=vercel-ai-orchestrion-v6-subscriber.js.map |
| {"version":3,"file":"vercel-ai-orchestrion-v6-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-orchestrion-v6-subscriber.ts"],"sourcesContent":["import type { Span } from '@sentry/core';\nimport { debug, getActiveSpan, SPAN_STATUS_ERROR, withActiveSpan } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\nimport { CHANNELS } from '../orchestrion/channels';\nimport { bindTracingChannelToSpan, type TracingChannelPayloadWithSpan } from '../tracing-channel';\nimport {\n clearOperationCallId,\n clearOperationId,\n createSpanFromMessage,\n enrichSpanOnEnd,\n type VercelAiChannelMessage,\n type VercelAiChannelOptions,\n type VercelAiTracingChannelFactory,\n} from './vercel-ai-dc-subscriber';\n\n/**\n * v6 channel adapter for the Vercel AI (`ai`) SDK.\n *\n * `ai` >= 7 publishes a normalized `ai:telemetry` tracing channel natively\n * (consumed by `subscribeVercelAiTracingChannel`). v6 has no such channel, so\n * orchestrion injects `orchestrion:ai:*` channels around the top-level\n * functions (see `orchestrion/config/index.ts`). The injected channels carry only the\n * wrapped call's `{ arguments, result, error }` — NOT v7's normalized `event`\n * object — so this adapter reconstructs an equivalent {@link VercelAiChannelMessage}\n * from v6's argument/result shapes and delegates to the SAME span-building core\n * (`createSpanFromMessage` / `enrichSpanOnEnd`) the v7 subscriber uses, so the\n * emitted spans are identical between v6 and v7.\n *\n * The model call (`languageModelCall` / `generate_content` span) has no\n * injectable definition in `ai`, so we instead wrap `resolveLanguageModel` (the\n * single chokepoint every model call flows through) and monkey-patch\n * `doGenerate`/`doStream` on the returned model.\n */\n\n/** Shape orchestrion's transform attaches to the tracing-channel context. */\ninterface OrchestrionContext {\n arguments: unknown[];\n result?: unknown;\n error?: unknown;\n}\n\n/** Builds the normalized message for a channel from the wrapped call's first-arg options. */\ntype MessageBuilder = (options: Record<string, unknown>, telemetry: Record<string, unknown>) => VercelAiChannelMessage;\n\n/** A resolved `ai` language model — has `doGenerate`/`doStream` and identity fields. */\ninterface ResolvedModel {\n modelId?: string;\n provider?: string;\n doGenerate?: (...args: unknown[]) => Promise<unknown>;\n doStream?: (...args: unknown[]) => Promise<unknown>;\n}\n\nconst PATCHED = Symbol('SentryVercelAiModelPatched');\n\n/** A resolved model with our patch bookkeeping (idempotency flag). */\ntype PatchableModel = ResolvedModel & { [PATCHED]?: boolean };\n\n// Per-operation correlation id. No Date/random (unavailable / non-deterministic) — a counter is enough.\nlet callIdCounter = 0;\nfunction nextCallId(): string {\n return `v6-${++callIdCounter}`;\n}\n\n// The message built on `start` for each operation, keyed by the (stable-identity) channel context, so\n// the `beforeSpanEnd` handler can enrich the span from the settled result and clear the `callId` maps.\nconst messages = new WeakMap<object, VercelAiChannelMessage>();\n// The spans we opened for top-level operations, and each one's `callId`. A model call resolves its\n// parent against this set (so it never mis-attributes to the enclosing `main`/user span) and reads the\n// parent's `callId` so its span can be named after the operation (e.g. `ai.streamText.doStream`).\nconst operationSpans = new WeakSet<Span>();\nconst callIdBySpan = new WeakMap<Span, string>();\n// The operation's per-call recording flags (`experimental_telemetry.recordInputs/recordOutputs`), keyed by\n// its span. A model call carries no telemetry of its own, so it inherits the enclosing operation's flags —\n// otherwise a per-call `recordInputs: true` would record inputs on the `invoke_agent` span but not on the\n// child `generate_content` span (whose event would fall back to the global default). v7's channel forwards\n// these flags on every event, so this keeps v6 identical.\nconst recordingBySpan = new WeakMap<Span, ReturnType<typeof recording>>();\n\n// The `experimental_telemetry` objects we swapped in to suppress `ai`'s native OTel spans (see\n// `suppressNativeTelemetry`). Our skip logic treats `isEnabled === false` as \"user disabled telemetry,\n// emit no span\"; without this set, a call whose options object we already neutralized — or a user-shared\n// telemetry object we replaced on a prior call — would be misread as user-disabled and lose its span.\nconst suppressedTelemetry = new WeakSet<object>();\n\nlet subscribed = false;\n\n/**\n * Subscribe the v6 orchestrion channel adapter. Safe to always call: inert on\n * `ai` >= 7 (those channels are never published) and when orchestrion injection\n * isn't active. Idempotent.\n *\n * `tracingChannel` is the platform-provided factory (the same one passed to\n * `subscribeVercelAiTracingChannel`); `options` pins the recording settings at\n * subscribe time so we never look the integration up per event.\n */\nexport function subscribeVercelAiOrchestrionChannels(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n try {\n bindOperation(tracingChannel, CHANNELS.VERCEL_AI_GENERATE_TEXT, buildTextMessage('generateText'), options);\n bindOperation(tracingChannel, CHANNELS.VERCEL_AI_STREAM_TEXT, buildTextMessage('streamText'), options);\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EMBED,\n (callOptions, telemetry) => ({\n type: 'embed',\n event: {\n callId: nextCallId(),\n ...modelFields(callOptions.model),\n maxRetries: callOptions.maxRetries,\n value: callOptions.value,\n ...recording(telemetry),\n },\n }),\n options,\n );\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EMBED_MANY,\n // `embedMany` takes a `values` array (vs `embed`'s single `value`); the shared core reads it as the\n // embeddings input, matching the OTel path's batch `ai.embedMany` span.\n (callOptions, telemetry) => ({\n type: 'embedMany',\n event: {\n callId: nextCallId(),\n ...modelFields(callOptions.model),\n maxRetries: callOptions.maxRetries,\n values: callOptions.values,\n ...recording(telemetry),\n },\n }),\n options,\n );\n bindOperation(\n tracingChannel,\n CHANNELS.VERCEL_AI_EXECUTE_TOOL_CALL,\n (callOptions, telemetry) => ({\n type: 'executeTool',\n // v6 carries the tool definitions on the executeToolCall args (a record keyed by name);\n // the shared core reads the matching tool's `description` for the span.\n event: {\n callId: nextCallId(),\n toolCall: callOptions.toolCall,\n tools: callOptions.tools,\n ...recording(telemetry),\n },\n }),\n options,\n );\n subscribeResolveLanguageModel(tracingChannel, CHANNELS.VERCEL_AI_RESOLVE_LANGUAGE_MODEL, options);\n } catch {\n DEBUG_BUILD && debug.log('Vercel AI orchestrion channel subscription failed.');\n }\n}\n\n/**\n * Bind one operation channel: `getSpan` opens a span from the message reconstructed out of the wrapped\n * call's first argument; `beforeSpanEnd` enriches it from the settled result (tokens, output messages,\n * finish reasons, …) before the helper ends the span.\n *\n * An operation whose `experimental_telemetry.isEnabled` is explicitly `false` is skipped entirely (no\n * span): the orchestrion channel fires regardless of that flag, whereas v7's native `ai:telemetry`\n * channel is simply not published in that case — so we reproduce v7's \"no telemetry → no span\".\n */\nfunction bindOperation(\n tracingChannel: VercelAiTracingChannelFactory,\n channelName: string,\n build: MessageBuilder,\n options: VercelAiChannelOptions,\n): void {\n const channel = tracingChannel<OrchestrionContext>(channelName);\n\n // Build the operation span from the wrapped call's first argument and track it (so a model call can\n // resolve it as its parent). `bindTracingChannelToSpan` calls this once at channel `start` and makes\n // the returned span the active async context for the operation's duration — that active span is what\n // `resolveModelCallParent` reads. It also sets `data._sentrySpan`, so we don't here.\n const buildOperationSpan = (data: TracingChannelPayloadWithSpan<OrchestrionContext>): Span | undefined => {\n const callOptions = isRecord(data.arguments[0]) ? data.arguments[0] : {};\n const telemetry = isRecord(callOptions.experimental_telemetry) ? callOptions.experimental_telemetry : {};\n // `isEnabled === false` means the user opted out — emit no span. But `isEnabled` is also `false` on\n // the telemetry object we swap in to suppress native spans, so don't mistake our own object for a\n // user opt-out (which would drop the span on a call whose options we already neutralized).\n if (telemetry.isEnabled === false && !suppressedTelemetry.has(telemetry)) {\n return undefined;\n }\n const message = build(callOptions, telemetry);\n // Stop `ai` from emitting its own native OTel spans for this call — we build the equivalent spans\n // from the channels, so the SDK's would be duplicates. Reads above have already captured everything\n // we need off `telemetry`.\n suppressNativeTelemetry(callOptions, telemetry);\n const span = createSpanFromMessage(message, options);\n if (span) {\n messages.set(data, message);\n operationSpans.add(span);\n const callId = asString(message.event.callId);\n if (callId) {\n callIdBySpan.set(span, callId);\n }\n recordingBySpan.set(span, recording(telemetry));\n }\n return span;\n };\n\n bindTracingChannelToSpan(\n channel,\n (data: TracingChannelPayloadWithSpan<OrchestrionContext>) => buildOperationSpan(data),\n {\n beforeSpanEnd: (span, data) => {\n const message = messages.get(data);\n if (!message) {\n return;\n }\n // The helper's `error` handler already set the span status; only enrich from a successful result.\n if (!('error' in data)) {\n // v6's `executeToolCall` returns the tool result/error object directly, whereas the shared core\n // (matching v7) expects it nested under `output`; wrap it so tool-error detection works.\n message.result = message.type === 'executeTool' ? { output: data.result } : data.result;\n enrichSpanOnEnd(span, message, options);\n }\n // A `streamText` model call runs after this (synchronously-returning) operation's span has\n // already ended, so its `callId` entry must outlive the operation — it's cleared once the model\n // call settles (see `patchModelMethod`). Every other operation can clear here.\n if (message.type !== 'streamText') {\n clearOperationId(message);\n }\n messages.delete(data);\n },\n },\n );\n}\n\n/**\n * Neutralize `ai`'s native OpenTelemetry instrumentation for this call by pointing\n * `experimental_telemetry` at a copy with `isEnabled: false`. `ai`'s `getTracer` then returns its\n * internal no-op tracer, so it never creates (nor sets active) the duplicate `ai.*` spans we'd\n * otherwise have to drop.\n *\n * Only a call that explicitly enabled telemetry emits native spans — otherwise `ai` already uses its\n * no-op tracer, so there's nothing to suppress and we leave the user's options untouched. When\n * `isEnabled === true`, `telemetry` is `callOptions.experimental_telemetry` and `callOptions` is the\n * real first argument the SDK will read, so the reassignment takes effect for the wrapped call. We\n * replace rather than mutate in place, so a telemetry object the user shares across calls keeps its own\n * `isEnabled: true`; the replacement is tracked in `suppressedTelemetry` so our skip logic doesn't\n * later read it back as a user opt-out.\n */\nfunction suppressNativeTelemetry(callOptions: Record<string, unknown>, telemetry: Record<string, unknown>): void {\n if (telemetry.isEnabled !== true) {\n return;\n }\n const suppressed = { ...telemetry, isEnabled: false };\n suppressedTelemetry.add(suppressed);\n callOptions.experimental_telemetry = suppressed;\n}\n\n/**\n * `resolveLanguageModel` returns the model every call flows through. We don't span it — on `end` we\n * monkey-patch `doGenerate`/`doStream` on the returned model so each invocation produces a\n * `languageModelCall` span parented to the enclosing invoke_agent span.\n */\nfunction subscribeResolveLanguageModel(\n tracingChannel: VercelAiTracingChannelFactory,\n channelName: string,\n options: VercelAiChannelOptions,\n): void {\n tracingChannel<OrchestrionContext>(channelName).subscribe({\n end(rawCtx) {\n const ctx = rawCtx as OrchestrionContext;\n if (!isRecord(ctx.result)) {\n return;\n }\n const model = ctx.result as PatchableModel;\n // Patch the model's `doGenerate`/`doStream` once. The model call recovers its parent from the\n // active async context at call time (the operation span `bindTracingChannelToSpan` bound), which\n // propagates into the model call for `streamText` too, so there is nothing to capture on the model here.\n if (!model[PATCHED]) {\n model[PATCHED] = true;\n patchModelMethod(model, 'doGenerate', options);\n patchModelMethod(model, 'doStream', options);\n }\n },\n start() {\n /* no-op */\n },\n asyncStart() {\n /* no-op */\n },\n asyncEnd() {\n /* no-op */\n },\n error() {\n /* no-op */\n },\n });\n}\n\n/**\n * Pick the invoke_agent span a model call should hang under: the operation span that\n * `bindTracingChannelToSpan` planted as the active async context for the enclosing operation.\n *\n * Because we suppress `ai`'s native telemetry (so it never installs its own span as active), the active\n * span inside `doGenerate`/`doStream` is our operation span. The `operationSpans` gate makes this return\n * `undefined` when the active span isn't one of ours — e.g. telemetry was disabled for the call so we\n * opened no operation span and the active span is the user's enclosing span — so the model call is\n * skipped rather than mis-parented.\n *\n * This covers `generateText`/`embed` (whose model call is awaited inside the operation body) and\n * `streamText` alike — `ai` initiates the stream synchronously within the operation's bound context, so\n * the later `doStream` continuation restores the same active span even though the operation's span has\n * already ended. The per-operation binding also disambiguates concurrent calls that share one model\n * instance (a single mutable slot on the shared model could not — it would hold whichever operation\n * resolved the model last).\n */\nfunction resolveModelCallParent(): Span | undefined {\n const active = getActiveSpan();\n return active && operationSpans.has(active) ? active : undefined;\n}\n\nfunction patchModelMethod(\n model: PatchableModel,\n method: 'doGenerate' | 'doStream',\n options: VercelAiChannelOptions,\n): void {\n const original = model[method];\n if (typeof original !== 'function') {\n return;\n }\n model[method] = function (this: unknown, ...args: unknown[]): Promise<unknown> {\n const parent = resolveModelCallParent();\n // No enclosing operation span (e.g. telemetry disabled for the call) → don't open a model-call span.\n if (!parent) {\n return Promise.resolve(original.apply(this, args));\n }\n\n const callArgs = isRecord(args[0]) ? args[0] : {};\n // Carry the operation's `callId` so the shared core can name the span after it\n // (`ai.generateText.doGenerate` / `ai.streamText.doStream`).\n const callId = callIdBySpan.get(parent);\n const message: VercelAiChannelMessage = {\n type: 'languageModelCall',\n event: {\n callId,\n provider: model.provider,\n modelId: model.modelId,\n tools: callArgs.tools,\n messages: callArgs.prompt,\n // Inherit the enclosing operation's per-call recording flags so inputs/tools/outputs are recorded on\n // the model-call span whenever they are on the parent `invoke_agent` span.\n ...recordingBySpan.get(parent),\n },\n };\n const span = withActiveSpan(parent, () => createSpanFromMessage(message, options));\n // `languageModelCall` always opens a span; the guard just keeps the wrapper safe if that changes.\n if (!span) {\n return Promise.resolve(original.apply(this, args));\n }\n\n // `streamText` ends its operation span synchronously, so its `callId` entry was deliberately left in\n // place for this later model call; drop it now that we've used it.\n const clearStreamCallId = (): void => {\n if (method === 'doStream' && callId) {\n clearOperationCallId(callId);\n }\n };\n\n // Both the synchronous throw and the async rejection of the model call must end the span with an\n // error status (an `async` `doGenerate`/`doStream` that throws rejects rather than throwing here).\n const failSpan = (error: unknown): never => {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: error instanceof Error ? error.message : 'unknown_error' });\n span.end();\n clearStreamCallId();\n throw error;\n };\n\n try {\n const result = Promise.resolve(original.apply(this, args));\n // `doStream` resolves to `{ stream, ... }` before the stream is consumed; we end here (start/end\n // bracket the call) to match the channel timing.\n return result.then(value => {\n message.result = value;\n enrichSpanOnEnd(span, message, options);\n span.end();\n clearStreamCallId();\n return value;\n }, failSpan);\n } catch (error) {\n return failSpan(error);\n }\n };\n}\n\nfunction buildTextMessage(type: 'generateText' | 'streamText'): MessageBuilder {\n return (options, telemetry) => ({\n type,\n event: {\n callId: nextCallId(),\n operationId: `ai.${type}`,\n functionId: asString(telemetry.functionId),\n ...modelFields(options.model),\n maxRetries: options.maxRetries,\n // Normalize to the message-array shape the shared core (and v7's channel) expects: a bare string\n // `prompt` becomes a single user message, matching the SDK's own normalization.\n messages: normalizePromptMessages(options),\n ...recording(telemetry),\n },\n });\n}\n\nfunction normalizePromptMessages(options: Record<string, unknown>): unknown {\n if (Array.isArray(options.messages)) {\n return options.messages;\n }\n if (typeof options.prompt === 'string') {\n return [{ role: 'user', content: options.prompt }];\n }\n return options.messages ?? options.prompt;\n}\n\nfunction recording(telemetry: Record<string, unknown>): { recordInputs: unknown; recordOutputs: unknown } {\n return { recordInputs: telemetry.recordInputs, recordOutputs: telemetry.recordOutputs };\n}\n\nfunction modelFields(model: unknown): { provider?: string; modelId?: string } {\n return { provider: modelField(model, 'provider'), modelId: modelField(model, 'modelId') };\n}\n\nfunction modelField(model: unknown, field: 'modelId' | 'provider'): string | undefined {\n return isRecord(model) ? asString(model[field]) : undefined;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n"],"names":[],"mappings":"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"} |
| import { AnthropicAiOptions } from '@sentry/core'; | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven Anthropic integration. Subscribes to the `orchestrion:@anthropic-ai/sdk:*` | ||
| * diagnostics_channels injected into the SDK's chat (`messages`/`completions`/beta `messages`), `models`, and | ||
| * `messages.stream()` methods, so it requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const anthropicChannelIntegration: (options?: AnthropicAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "Anthropic_AI"; | ||
| }; | ||
| //# sourceMappingURL=anthropic.d.ts.map |
| declare const LIFECYCLE_EXT_POINTS: readonly [ | ||
| "onPreAuth", | ||
| "onCredentials", | ||
| "onPostAuth", | ||
| "onPreHandler", | ||
| "onPostHandler", | ||
| "onPreResponse", | ||
| "onRequest" | ||
| ]; | ||
| export type ServerRequestExtType = (typeof LIFECYCLE_EXT_POINTS)[number]; | ||
| export type LifecycleMethod = (request: unknown, h: unknown, err?: Error) => unknown; | ||
| export interface ServerRouteOptions { | ||
| handler?: LifecycleMethod | unknown; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerRoute { | ||
| path: string; | ||
| method: string; | ||
| handler?: LifecycleMethod | unknown; | ||
| options?: ((server: unknown) => ServerRouteOptions) | ServerRouteOptions; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtEventsObject { | ||
| type: string; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtEventsRequestObject { | ||
| type: ServerRequestExtType; | ||
| method: LifecycleMethod; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtOptions { | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * This symbol is used to mark a Hapi route handler or server extension handler as | ||
| * already patched, since it's possible to use these handlers multiple times | ||
| * i.e. when allowing multiple versions of one plugin, or when registering a plugin | ||
| * multiple times on different servers. | ||
| */ | ||
| export declare const handlerPatched: unique symbol; | ||
| export type PatchableServerRoute = ServerRoute & { | ||
| [handlerPatched]?: boolean; | ||
| }; | ||
| export type PatchableExtMethod = LifecycleMethod & { | ||
| [handlerPatched]?: boolean; | ||
| }; | ||
| export type ServerExtDirectInput = [ | ||
| ServerRequestExtType, | ||
| LifecycleMethod, | ||
| (ServerExtOptions | undefined)? | ||
| ]; | ||
| export declare const HapiLayerType: { | ||
| readonly ROUTER: "router"; | ||
| readonly PLUGIN: "plugin"; | ||
| readonly EXT: "server.ext"; | ||
| }; | ||
| export declare const HapiLifecycleMethodNames: Set<string>; | ||
| export declare enum AttributeNames { | ||
| HAPI_TYPE = "hapi.type", | ||
| PLUGIN_NAME = "hapi.plugin.name", | ||
| EXT_TYPE = "server.ext.type" | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=hapi-types.d.ts.map |
| import { ServerRequestExtType, ServerRoute } from './hapi-types'; | ||
| type SpanAttributes = Record<string, string | undefined>; | ||
| interface SpanMetadata { | ||
| attributes: SpanAttributes; | ||
| name: string; | ||
| } | ||
| /** Build the span name and attributes for a Hapi route. */ | ||
| export declare const getRouteMetadata: (route: ServerRoute, pluginName?: string) => SpanMetadata; | ||
| /** Build the span name and attributes for a Hapi server extension. */ | ||
| export declare const getExtMetadata: (extPoint: ServerRequestExtType, pluginName?: string, methodName?: string) => SpanMetadata; | ||
| /** | ||
| * Wrap the route handler(s) in the live `server.route` arguments array, mutating | ||
| * `args[0]` in place. `args[0]` is either a single route options object or an | ||
| * array of them. Idempotent via the `handlerPatched` marker. | ||
| */ | ||
| export declare function wrapRouteArguments(args: unknown[], pluginName?: string): void; | ||
| /** | ||
| * Wrap the extension method(s) in the live `server.ext` arguments array, | ||
| * mutating `args` in place. Handles the three accepted input shapes: | ||
| * `(eventsArray)`, `(lifecycleEventObject)`, and `(extTypeString, method, options)`. | ||
| * Idempotent via the `handlerPatched` marker. | ||
| */ | ||
| export declare function wrapExtArguments(args: unknown[], pluginName?: string): void; | ||
| export {}; | ||
| //# sourceMappingURL=hapi-utils.d.ts.map |
| /** | ||
| * EXPERIMENTAL — orchestrion-driven hapi integration. Subscribes to the | ||
| * `orchestrion:@hapi/hapi:route` / `:ext` channels injected into `@hapi/hapi`'s | ||
| * `lib/server.js`. Requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const hapiChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Hapi"; | ||
| }; | ||
| //# sourceMappingURL=hapi.d.ts.map |
| import { Span } from '@sentry/core'; | ||
| /** Mirrors `@opentelemetry/instrumentation-ioredis`' response hook. Not called for failed commands. */ | ||
| export type IORedisResponseHook = (span: Span, command: string, args: Array<string | Buffer>, result: unknown) => void; | ||
| export interface IORedisChannelIntegrationOptions { | ||
| responseHook?: IORedisResponseHook; | ||
| } | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven ioredis integration. Subscribes to | ||
| * `orchestrion:ioredis:command` / `:connect` (injected into ioredis' `<5.11.0` | ||
| * `sendCommand`/`connect`) and creates db spans matching | ||
| * `@opentelemetry/instrumentation-ioredis`. Requires the orchestrion runtime hook | ||
| * or bundler plugin. | ||
| */ | ||
| export declare const ioredisChannelIntegration: (options?: IORedisChannelIntegrationOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "IORedis"; | ||
| }; | ||
| //# sourceMappingURL=ioredis.d.ts.map |
| import { OpenAiOptions } from '@sentry/core'; | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven OpenAI integration. Subscribes to the `orchestrion:openai:*` | ||
| * diagnostics_channels injected into `openai`'s `create` methods (chat completions, responses, embeddings, | ||
| * conversations), so it requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const openaiChannelIntegration: (options?: OpenAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "OpenAI"; | ||
| }; | ||
| //# sourceMappingURL=openai.d.ts.map |
| /** | ||
| * EXPERIMENTAL: orchestrion-driven `pg` (node-postgres) integration. | ||
| * | ||
| * Subscribes to the `orchestrion:pg:query`/`:connect` and | ||
| * `orchestrion:pg-pool:connect` diagnostics_channels that the orchestrion code | ||
| * transform injects into `pg`'s `Client.prototype.query`/`connect` | ||
| * and `pg-pool`'s `Pool.prototype.connect`. Requires the orchestrion runtime | ||
| * hook or bundler plugin to be active. | ||
| */ | ||
| export declare const postgresChannelIntegration: (options?: { | ||
| ignoreConnectSpans?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "Postgres"; | ||
| }; | ||
| //# sourceMappingURL=postgres.d.ts.map |
| /** | ||
| * Auto-instrument the `ai` SDK. Supported are: | ||
| * - v7 via native `ai:telemetry` tracing channel | ||
| * - v6 via orchestrion `orchestrion:ai:*` channels | ||
| */ | ||
| export declare const vercelAiChannelIntegration: (options?: { | ||
| recordInputs?: boolean; | ||
| recordOutputs?: boolean; | ||
| enableTruncation?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| //# sourceMappingURL=vercel-ai.d.ts.map |
| /** | ||
| * Auto-instrument the [mongoose](https://www.npmjs.com/package/mongoose) library via its native | ||
| * `node:diagnostics_channel` tracing channels (mongoose >= 9.7). | ||
| * | ||
| * On older mongoose versions the channels are never published to, so this integration is inert and | ||
| * the IITM-based patcher (gated to `< 9.7.0`) handles instrumentation instead. | ||
| */ | ||
| export declare const mongooseIntegration: () => import("@sentry/core").Integration & { | ||
| name: string; | ||
| }; | ||
| //# sourceMappingURL=index.d.ts.map |
| import { TracingChannel } from 'node:diagnostics_channel'; | ||
| export declare const MONGOOSE_DC_CHANNEL_QUERY = "mongoose:query"; | ||
| export declare const MONGOOSE_DC_CHANNEL_AGGREGATE = "mongoose:aggregate"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_SAVE = "mongoose:model:save"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = "mongoose:model:insertMany"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = "mongoose:model:bulkWrite"; | ||
| export declare const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = "mongoose:cursor:next"; | ||
| /** | ||
| * Shape of the context object mongoose >= 9.7.0 publishes on its tracing | ||
| * channels (mongoose's `TracingContext`, see `types/tracing.d.ts`). | ||
| * | ||
| * Node's `tracePromise` mutates this same object with `result`/`error` once the | ||
| * operation settles, which `bindTracingChannelToSpan` reads in its lifecycle | ||
| * handlers — hence both are declared optional here. | ||
| * | ||
| * Unlike redis/ioredis, mongoose does NOT pre-sanitize the payload, so `args` | ||
| * carries the raw user query. We redact it before emitting `db.query.text`. | ||
| */ | ||
| export interface MongooseTracingData { | ||
| operation: string; | ||
| /** Absent for connection-level `aggregate()` calls, which have no model/collection. */ | ||
| collection?: string; | ||
| database?: string; | ||
| serverAddress?: string; | ||
| serverPort?: number; | ||
| /** Cursor channels only: the cursor's fetch batch size and tailable flag. */ | ||
| batchSize?: number; | ||
| tailable?: boolean; | ||
| /** | ||
| * Operation-specific arguments. `filter` (queries/cursors) and `pipeline` | ||
| * (aggregations) carry the query shape; `docs`/`ops` carry batch payloads. | ||
| */ | ||
| args?: { | ||
| filter?: unknown; | ||
| pipeline?: unknown; | ||
| docs?: unknown; | ||
| ops?: unknown; | ||
| [key: string]: unknown; | ||
| }; | ||
| result?: unknown; | ||
| error?: Error; | ||
| } | ||
| /** | ||
| * Platform-provided factory that creates a native tracing channel for the given name. The | ||
| * subscriber binds the span and its lifecycle onto the channel via `bindTracingChannelToSpan`, | ||
| * which propagates the active span through the runtime's async context. | ||
| * | ||
| * Node passes `node:diagnostics_channel`'s `tracingChannel` directly. | ||
| */ | ||
| export type MongooseTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| /** | ||
| * Subscribe Sentry span handlers to mongoose's diagnostics-channel events | ||
| * (`mongoose:query`, `:aggregate`, `:model:save`, `:model:insertMany`, | ||
| * `:model:bulkWrite`, `:cursor:next`), published by mongoose >= 9.7.0. | ||
| * | ||
| * On older mongoose versions the channels are never published to, so the | ||
| * subscribers are inert — there is no double-instrumentation against the | ||
| * IITM-based vendored patcher, which is gated to `< 9.7.0`. | ||
| * | ||
| * Idempotent: subsequent calls are a no-op. | ||
| */ | ||
| export declare function subscribeMongooseDiagnosticChannels(tracingChannel: MongooseTracingChannelFactory): void; | ||
| //# sourceMappingURL=mongoose-dc-subscriber.d.ts.map |
| export declare const anthropicAiConfig: ({ | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| } | { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Sync"; | ||
| }; | ||
| })[]; | ||
| export declare const anthropicAiChannels: { | ||
| readonly ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat"; | ||
| readonly ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models"; | ||
| readonly ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream"; | ||
| }; | ||
| //# sourceMappingURL=anthropic-ai.d.ts.map |
| export declare const hapiConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| methodName: string; | ||
| kind: "Sync"; | ||
| }; | ||
| }[]; | ||
| export declare const hapiChannels: { | ||
| readonly HAPI_ROUTE: "orchestrion:@hapi/hapi:route"; | ||
| readonly HAPI_EXT: "orchestrion:@hapi/hapi:ext"; | ||
| }; | ||
| //# sourceMappingURL=hapi.d.ts.map |
| import { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[]; | ||
| /** | ||
| * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS` | ||
| * (e.g. `['mysql']`). | ||
| * | ||
| * Bundler plugins MUST ensure these are actually bundled rather than | ||
| * externalized: an externalized dependency is resolved from `node_modules` at | ||
| * runtime and never passes through the code transform's `onLoad`, so its | ||
| * diagnostics_channel calls are silently never injected. | ||
| */ | ||
| export declare const INSTRUMENTED_MODULE_NAMES: string[]; | ||
| /** | ||
| * Returns `external` with any instrumented packages removed, so a bundler that | ||
| * uses an "external" denylist (esbuild, Bun, Rollup) still bundles — and thus | ||
| * transforms — them. Matches an exact package name (`'mysql'`) or a subpath | ||
| * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined` | ||
| * is returned unchanged. | ||
| * | ||
| * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes | ||
| * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.) | ||
| */ | ||
| export declare function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined; | ||
| //# sourceMappingURL=index.d.ts.map |
| import { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const ioredisConfig: InstrumentationConfig[]; | ||
| export declare const ioredisChannels: { | ||
| readonly IOREDIS_COMMAND: "orchestrion:ioredis:command"; | ||
| readonly IOREDIS_CONNECT: "orchestrion:ioredis:connect"; | ||
| }; | ||
| //# sourceMappingURL=ioredis.d.ts.map |
| export declare const lruMemoizerConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| functionName: string; | ||
| kind: "Callback"; | ||
| }; | ||
| }[]; | ||
| export declare const lruMemoizerChannels: { | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| }; | ||
| //# sourceMappingURL=lru-memoizer.d.ts.map |
| export declare const mysqlConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| expressionName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| }[]; | ||
| export declare const mysqlChannels: { | ||
| readonly MYSQL_QUERY: "orchestrion:mysql:query"; | ||
| }; | ||
| //# sourceMappingURL=mysql.d.ts.map |
| export declare const openaiConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| }[]; | ||
| export declare const openaiChannels: { | ||
| readonly OPENAI_CHAT: "orchestrion:openai:chat"; | ||
| readonly OPENAI_RESPONSES: "orchestrion:openai:responses"; | ||
| readonly OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings"; | ||
| readonly OPENAI_CONVERSATIONS: "orchestrion:openai:conversations"; | ||
| }; | ||
| //# sourceMappingURL=openai.d.ts.map |
| export declare const pgConfig: ({ | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| expressionName?: undefined; | ||
| }; | ||
| } | { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| expressionName: string; | ||
| kind: "Auto"; | ||
| className?: undefined; | ||
| methodName?: undefined; | ||
| }; | ||
| })[]; | ||
| export declare const pgChannels: { | ||
| readonly PG_QUERY: "orchestrion:pg:query"; | ||
| readonly PG_CONNECT: "orchestrion:pg:connect"; | ||
| readonly PGPOOL_CONNECT: "orchestrion:pg-pool:connect"; | ||
| }; | ||
| //# sourceMappingURL=pg.d.ts.map |
| import { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const vercelAiConfig: InstrumentationConfig[]; | ||
| export declare const vercelAiChannels: { | ||
| readonly VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText"; | ||
| readonly VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText"; | ||
| readonly VERCEL_AI_EMBED: "orchestrion:ai:embed"; | ||
| readonly VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany"; | ||
| readonly VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall"; | ||
| readonly VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel"; | ||
| }; | ||
| //# sourceMappingURL=vercel-ai.d.ts.map |
| /** | ||
| * Given the redis command name and arguments, return a combination of the | ||
| * command name + the allowed arguments according to `serializationSubsets`. | ||
| */ | ||
| export declare const defaultDbStatementSerializer: (cmdName: string, cmdArgs: Array<string | Buffer | number | unknown[]>) => string; | ||
| //# sourceMappingURL=redis-statement-serializer.d.ts.map |
| import { VercelAiChannelOptions, VercelAiTracingChannelFactory } from './vercel-ai-dc-subscriber'; | ||
| /** | ||
| * Subscribe the v6 orchestrion channel adapter. Safe to always call: inert on | ||
| * `ai` >= 7 (those channels are never published) and when orchestrion injection | ||
| * isn't active. Idempotent. | ||
| * | ||
| * `tracingChannel` is the platform-provided factory (the same one passed to | ||
| * `subscribeVercelAiTracingChannel`); `options` pins the recording settings at | ||
| * subscribe time so we never look the integration up per event. | ||
| */ | ||
| export declare function subscribeVercelAiOrchestrionChannels(tracingChannel: VercelAiTracingChannelFactory, options?: VercelAiChannelOptions): void; | ||
| //# sourceMappingURL=vercel-ai-orchestrion-v6-subscriber.d.ts.map |
| import type { AnthropicAiOptions } from '@sentry/core'; | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven Anthropic integration. Subscribes to the `orchestrion:@anthropic-ai/sdk:*` | ||
| * diagnostics_channels injected into the SDK's chat (`messages`/`completions`/beta `messages`), `models`, and | ||
| * `messages.stream()` methods, so it requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const anthropicChannelIntegration: (options?: AnthropicAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "Anthropic_AI"; | ||
| }; | ||
| //# sourceMappingURL=anthropic.d.ts.map |
| {"version":3,"file":"anthropic.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/anthropic.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,kBAAkB,EAAgE,MAAM,cAAc,CAAC;AAgLrH;;;;GAIG;AACH,eAAO,MAAM,2BAA2B;;CAAkD,CAAC"} |
| declare const LIFECYCLE_EXT_POINTS: readonly ["onPreAuth", "onCredentials", "onPostAuth", "onPreHandler", "onPostHandler", "onPreResponse", "onRequest"]; | ||
| export type ServerRequestExtType = (typeof LIFECYCLE_EXT_POINTS)[number]; | ||
| export type LifecycleMethod = (request: unknown, h: unknown, err?: Error) => unknown; | ||
| export interface ServerRouteOptions { | ||
| handler?: LifecycleMethod | unknown; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerRoute { | ||
| path: string; | ||
| method: string; | ||
| handler?: LifecycleMethod | unknown; | ||
| options?: ((server: unknown) => ServerRouteOptions) | ServerRouteOptions; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtEventsObject { | ||
| type: string; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtEventsRequestObject { | ||
| type: ServerRequestExtType; | ||
| method: LifecycleMethod; | ||
| [key: string]: unknown; | ||
| } | ||
| export interface ServerExtOptions { | ||
| [key: string]: unknown; | ||
| } | ||
| /** | ||
| * This symbol is used to mark a Hapi route handler or server extension handler as | ||
| * already patched, since it's possible to use these handlers multiple times | ||
| * i.e. when allowing multiple versions of one plugin, or when registering a plugin | ||
| * multiple times on different servers. | ||
| */ | ||
| export declare const handlerPatched: unique symbol; | ||
| export type PatchableServerRoute = ServerRoute & { | ||
| [handlerPatched]?: boolean; | ||
| }; | ||
| export type PatchableExtMethod = LifecycleMethod & { | ||
| [handlerPatched]?: boolean; | ||
| }; | ||
| export type ServerExtDirectInput = [ServerRequestExtType, LifecycleMethod, (ServerExtOptions | undefined)?]; | ||
| export declare const HapiLayerType: { | ||
| readonly ROUTER: "router"; | ||
| readonly PLUGIN: "plugin"; | ||
| readonly EXT: "server.ext"; | ||
| }; | ||
| export declare const HapiLifecycleMethodNames: Set<string>; | ||
| export declare enum AttributeNames { | ||
| HAPI_TYPE = "hapi.type", | ||
| PLUGIN_NAME = "hapi.plugin.name", | ||
| EXT_TYPE = "server.ext.type" | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=hapi-types.d.ts.map |
| {"version":3,"file":"hapi-types.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/hapi-types.ts"],"names":[],"mappings":"AAUA,QAAA,MAAM,oBAAoB,sHAQhB,CAAC;AAEX,MAAM,MAAM,oBAAoB,GAAG,CAAC,OAAO,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEzE,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,GAAG,CAAC,EAAE,KAAK,KAAK,OAAO,CAAC;AAErF,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC;IACpC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC;IACpC,OAAO,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,kBAAkB,CAAC,GAAG,kBAAkB,CAAC;IACzE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,4BAA4B;IAC3C,IAAI,EAAE,oBAAoB,CAAC;IAC3B,MAAM,EAAE,eAAe,CAAC;IACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,EAAE,OAAO,MAAuC,CAAC;AAE5E,MAAM,MAAM,oBAAoB,GAAG,WAAW,GAAG;IAC/C,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG,eAAe,GAAG;IACjD,CAAC,cAAc,CAAC,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,oBAAoB,GAAG,CAAC,oBAAoB,EAAE,eAAe,EAAE,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAAC,CAAC,CAAC;AAE5G,eAAO,MAAM,aAAa;;;;CAIhB,CAAC;AAEX,eAAO,MAAM,wBAAwB,aAAwC,CAAC;AAE9E,oBAAY,cAAc;IACxB,SAAS,cAAc;IACvB,WAAW,qBAAqB;IAChC,QAAQ,oBAAoB;CAC7B"} |
| import type { ServerRequestExtType, ServerRoute } from './hapi-types'; | ||
| type SpanAttributes = Record<string, string | undefined>; | ||
| interface SpanMetadata { | ||
| attributes: SpanAttributes; | ||
| name: string; | ||
| } | ||
| /** Build the span name and attributes for a Hapi route. */ | ||
| export declare const getRouteMetadata: (route: ServerRoute, pluginName?: string) => SpanMetadata; | ||
| /** Build the span name and attributes for a Hapi server extension. */ | ||
| export declare const getExtMetadata: (extPoint: ServerRequestExtType, pluginName?: string, methodName?: string) => SpanMetadata; | ||
| /** | ||
| * Wrap the route handler(s) in the live `server.route` arguments array, mutating | ||
| * `args[0]` in place. `args[0]` is either a single route options object or an | ||
| * array of them. Idempotent via the `handlerPatched` marker. | ||
| */ | ||
| export declare function wrapRouteArguments(args: unknown[], pluginName?: string): void; | ||
| /** | ||
| * Wrap the extension method(s) in the live `server.ext` arguments array, | ||
| * mutating `args` in place. Handles the three accepted input shapes: | ||
| * `(eventsArray)`, `(lifecycleEventObject)`, and `(extTypeString, method, options)`. | ||
| * Idempotent via the `handlerPatched` marker. | ||
| */ | ||
| export declare function wrapExtArguments(args: unknown[], pluginName?: string): void; | ||
| export {}; | ||
| //# sourceMappingURL=hapi-utils.d.ts.map |
| {"version":3,"file":"hapi-utils.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/hapi-utils.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAOV,oBAAoB,EACpB,WAAW,EAEZ,MAAM,cAAc,CAAC;AAKtB,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAEzD,UAAU,YAAY;IACpB,UAAU,EAAE,cAAc,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;CACd;AAgDD,2DAA2D;AAC3D,eAAO,MAAM,gBAAgB,GAAI,OAAO,WAAW,EAAE,aAAa,MAAM,KAAG,YAkB1E,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,cAAc,GACzB,UAAU,oBAAoB,EAC9B,aAAa,MAAM,EACnB,aAAa,MAAM,KAClB,YAuBF,CAAC;AAoFF;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAS7E;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAwB3E"} |
| /** | ||
| * EXPERIMENTAL — orchestrion-driven hapi integration. Subscribes to the | ||
| * `orchestrion:@hapi/hapi:route` / `:ext` channels injected into `@hapi/hapi`'s | ||
| * `lib/server.js`. Requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const hapiChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Hapi"; | ||
| }; | ||
| //# sourceMappingURL=hapi.d.ts.map |
| {"version":3,"file":"hapi.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/hapi.ts"],"names":[],"mappings":"AAgEA;;;;GAIG;AACH,eAAO,MAAM,sBAAsB;;CAA6C,CAAC"} |
| import type { Span } from '@sentry/core'; | ||
| /** Mirrors `@opentelemetry/instrumentation-ioredis`' response hook. Not called for failed commands. */ | ||
| export type IORedisResponseHook = (span: Span, command: string, args: Array<string | Buffer>, result: unknown) => void; | ||
| export interface IORedisChannelIntegrationOptions { | ||
| responseHook?: IORedisResponseHook; | ||
| } | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven ioredis integration. Subscribes to | ||
| * `orchestrion:ioredis:command` / `:connect` (injected into ioredis' `<5.11.0` | ||
| * `sendCommand`/`connect`) and creates db spans matching | ||
| * `@opentelemetry/instrumentation-ioredis`. Requires the orchestrion runtime hook | ||
| * or bundler plugin. | ||
| */ | ||
| export declare const ioredisChannelIntegration: (options?: IORedisChannelIntegrationOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "IORedis"; | ||
| }; | ||
| //# sourceMappingURL=ioredis.d.ts.map |
| {"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/ioredis.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAiB,IAAI,EAAE,MAAM,cAAc,CAAC;AAwBxD,uGAAuG;AACvG,MAAM,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;AAEvH,MAAM,WAAW,gCAAgC;IAC/C,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAoHD;;;;;;GAMG;AACH,eAAO,MAAM,yBAAyB;;CAAgD,CAAC"} |
| import type { OpenAiOptions } from '@sentry/core'; | ||
| /** | ||
| * EXPERIMENTAL — orchestrion-driven OpenAI integration. Subscribes to the `orchestrion:openai:*` | ||
| * diagnostics_channels injected into `openai`'s `create` methods (chat completions, responses, embeddings, | ||
| * conversations), so it requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const openaiChannelIntegration: (options?: OpenAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "OpenAI"; | ||
| }; | ||
| //# sourceMappingURL=openai.d.ts.map |
| {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/openai.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAiB,aAAa,EAA4B,MAAM,cAAc,CAAC;AA6I3F;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;;CAA+C,CAAC"} |
| /** | ||
| * EXPERIMENTAL: orchestrion-driven `pg` (node-postgres) integration. | ||
| * | ||
| * Subscribes to the `orchestrion:pg:query`/`:connect` and | ||
| * `orchestrion:pg-pool:connect` diagnostics_channels that the orchestrion code | ||
| * transform injects into `pg`'s `Client.prototype.query`/`connect` | ||
| * and `pg-pool`'s `Pool.prototype.connect`. Requires the orchestrion runtime | ||
| * hook or bundler plugin to be active. | ||
| */ | ||
| export declare const postgresChannelIntegration: (options?: { | ||
| ignoreConnectSpans?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "Postgres"; | ||
| }; | ||
| //# sourceMappingURL=postgres.d.ts.map |
| {"version":3,"file":"postgres.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/postgres.ts"],"names":[],"mappings":"AAsRA;;;;;;;;GAQG;AACH,eAAO,MAAM,0BAA0B;yBA9M+B,OAAO;;;CA8MW,CAAC"} |
| /** | ||
| * Auto-instrument the `ai` SDK. Supported are: | ||
| * - v7 via native `ai:telemetry` tracing channel | ||
| * - v6 via orchestrion `orchestrion:ai:*` channels | ||
| */ | ||
| export declare const vercelAiChannelIntegration: (options?: { | ||
| recordInputs?: boolean; | ||
| recordOutputs?: boolean; | ||
| enableTruncation?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| //# sourceMappingURL=vercel-ai.d.ts.map |
| {"version":3,"file":"vercel-ai.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/vercel-ai.ts"],"names":[],"mappings":"AAkCA;;;;GAIG;AACH,eAAO,MAAM,0BAA0B;;;;;;CAAiD,CAAC"} |
| /** | ||
| * Auto-instrument the [mongoose](https://www.npmjs.com/package/mongoose) library via its native | ||
| * `node:diagnostics_channel` tracing channels (mongoose >= 9.7). | ||
| * | ||
| * On older mongoose versions the channels are never published to, so this integration is inert and | ||
| * the IITM-based patcher (gated to `< 9.7.0`) handles instrumentation instead. | ||
| */ | ||
| export declare const mongooseIntegration: () => import("@sentry/core").Integration & { | ||
| name: string; | ||
| }; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/mongoose/index.ts"],"names":[],"mappings":"AAsBA;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB;;CAA0C,CAAC"} |
| import type { TracingChannel } from 'node:diagnostics_channel'; | ||
| export declare const MONGOOSE_DC_CHANNEL_QUERY = "mongoose:query"; | ||
| export declare const MONGOOSE_DC_CHANNEL_AGGREGATE = "mongoose:aggregate"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_SAVE = "mongoose:model:save"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_INSERT_MANY = "mongoose:model:insertMany"; | ||
| export declare const MONGOOSE_DC_CHANNEL_MODEL_BULK_WRITE = "mongoose:model:bulkWrite"; | ||
| export declare const MONGOOSE_DC_CHANNEL_CURSOR_NEXT = "mongoose:cursor:next"; | ||
| /** | ||
| * Shape of the context object mongoose >= 9.7.0 publishes on its tracing | ||
| * channels (mongoose's `TracingContext`, see `types/tracing.d.ts`). | ||
| * | ||
| * Node's `tracePromise` mutates this same object with `result`/`error` once the | ||
| * operation settles, which `bindTracingChannelToSpan` reads in its lifecycle | ||
| * handlers — hence both are declared optional here. | ||
| * | ||
| * Unlike redis/ioredis, mongoose does NOT pre-sanitize the payload, so `args` | ||
| * carries the raw user query. We redact it before emitting `db.query.text`. | ||
| */ | ||
| export interface MongooseTracingData { | ||
| operation: string; | ||
| /** Absent for connection-level `aggregate()` calls, which have no model/collection. */ | ||
| collection?: string; | ||
| database?: string; | ||
| serverAddress?: string; | ||
| serverPort?: number; | ||
| /** Cursor channels only: the cursor's fetch batch size and tailable flag. */ | ||
| batchSize?: number; | ||
| tailable?: boolean; | ||
| /** | ||
| * Operation-specific arguments. `filter` (queries/cursors) and `pipeline` | ||
| * (aggregations) carry the query shape; `docs`/`ops` carry batch payloads. | ||
| */ | ||
| args?: { | ||
| filter?: unknown; | ||
| pipeline?: unknown; | ||
| docs?: unknown; | ||
| ops?: unknown; | ||
| [key: string]: unknown; | ||
| }; | ||
| result?: unknown; | ||
| error?: Error; | ||
| } | ||
| /** | ||
| * Platform-provided factory that creates a native tracing channel for the given name. The | ||
| * subscriber binds the span and its lifecycle onto the channel via `bindTracingChannelToSpan`, | ||
| * which propagates the active span through the runtime's async context. | ||
| * | ||
| * Node passes `node:diagnostics_channel`'s `tracingChannel` directly. | ||
| */ | ||
| export type MongooseTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| /** | ||
| * Subscribe Sentry span handlers to mongoose's diagnostics-channel events | ||
| * (`mongoose:query`, `:aggregate`, `:model:save`, `:model:insertMany`, | ||
| * `:model:bulkWrite`, `:cursor:next`), published by mongoose >= 9.7.0. | ||
| * | ||
| * On older mongoose versions the channels are never published to, so the | ||
| * subscribers are inert — there is no double-instrumentation against the | ||
| * IITM-based vendored patcher, which is gated to `< 9.7.0`. | ||
| * | ||
| * Idempotent: subsequent calls are a no-op. | ||
| */ | ||
| export declare function subscribeMongooseDiagnosticChannels(tracingChannel: MongooseTracingChannelFactory): void; | ||
| //# sourceMappingURL=mongoose-dc-subscriber.d.ts.map |
| {"version":3,"file":"mongoose-dc-subscriber.d.ts","sourceRoot":"","sources":["../../../src/mongoose/mongoose-dc-subscriber.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAmB/D,eAAO,MAAM,yBAAyB,mBAAmB,CAAC;AAC1D,eAAO,MAAM,6BAA6B,uBAAuB,CAAC;AAClE,eAAO,MAAM,8BAA8B,wBAAwB,CAAC;AACpE,eAAO,MAAM,qCAAqC,8BAA8B,CAAC;AACjF,eAAO,MAAM,oCAAoC,6BAA6B,CAAC;AAC/E,eAAO,MAAM,+BAA+B,yBAAyB,CAAC;AAStE;;;;;;;;;;GAUG;AACH,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,uFAAuF;IACvF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAE;QACL,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,GAAG,CAAC,EAAE,OAAO,CAAC;QACd,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KACxB,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED;;;;;;GAMG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAIrG;;;;;;;;;;GAUG;AACH,wBAAgB,mCAAmC,CAAC,cAAc,EAAE,6BAA6B,GAAG,IAAI,CAkBvG"} |
| export declare const anthropicAiConfig: ({ | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| } | { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Sync"; | ||
| }; | ||
| })[]; | ||
| export declare const anthropicAiChannels: { | ||
| readonly ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat"; | ||
| readonly ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models"; | ||
| readonly ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream"; | ||
| }; | ||
| //# sourceMappingURL=anthropic-ai.d.ts.map |
| {"version":3,"file":"anthropic-ai.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/anthropic-ai.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;IA+BK,CAAC;AAEpC,eAAO,MAAM,mBAAmB;;;;CAItB,CAAC"} |
| export declare const hapiConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| methodName: string; | ||
| kind: "Sync"; | ||
| }; | ||
| }[]; | ||
| export declare const hapiChannels: { | ||
| readonly HAPI_ROUTE: "orchestrion:@hapi/hapi:route"; | ||
| readonly HAPI_EXT: "orchestrion:@hapi/hapi:ext"; | ||
| }; | ||
| //# sourceMappingURL=hapi.d.ts.map |
| {"version":3,"file":"hapi.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/hapi.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU;;;;;;;;;;;GAeY,CAAC;AAEpC,eAAO,MAAM,YAAY;;;CAGf,CAAC"} |
| import type { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[]; | ||
| /** | ||
| * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS` | ||
| * (e.g. `['mysql']`). | ||
| * | ||
| * Bundler plugins MUST ensure these are actually bundled rather than | ||
| * externalized: an externalized dependency is resolved from `node_modules` at | ||
| * runtime and never passes through the code transform's `onLoad`, so its | ||
| * diagnostics_channel calls are silently never injected. | ||
| */ | ||
| export declare const INSTRUMENTED_MODULE_NAMES: string[]; | ||
| /** | ||
| * Returns `external` with any instrumented packages removed, so a bundler that | ||
| * uses an "external" denylist (esbuild, Bun, Rollup) still bundles — and thus | ||
| * transforms — them. Matches an exact package name (`'mysql'`) or a subpath | ||
| * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined` | ||
| * is returned unchanged. | ||
| * | ||
| * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes | ||
| * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.) | ||
| */ | ||
| export declare function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAU7E,eAAO,MAAM,uBAAuB,EAAE,qBAAqB,EAS1D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,EAAyE,CAAC;AAExH;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAO1G"} |
| import type { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const ioredisConfig: InstrumentationConfig[]; | ||
| export declare const ioredisChannels: { | ||
| readonly IOREDIS_COMMAND: "orchestrion:ioredis:command"; | ||
| readonly IOREDIS_CONNECT: "orchestrion:ioredis:connect"; | ||
| }; | ||
| //# sourceMappingURL=ioredis.d.ts.map |
| {"version":3,"file":"ioredis.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/ioredis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,eAAO,MAAM,aAAa,yBAwBS,CAAC;AAEpC,eAAO,MAAM,eAAe;;;CAGlB,CAAC"} |
| export declare const lruMemoizerConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| functionName: string; | ||
| kind: "Callback"; | ||
| }; | ||
| }[]; | ||
| export declare const lruMemoizerChannels: { | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| }; | ||
| //# sourceMappingURL=lru-memoizer.d.ts.map |
| {"version":3,"file":"lru-memoizer.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/lru-memoizer.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,iBAAiB;;;;;;;;;;;GAOK,CAAC;AAEpC,eAAO,MAAM,mBAAmB;;CAEtB,CAAC"} |
| export declare const mysqlConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| expressionName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| }[]; | ||
| export declare const mysqlChannels: { | ||
| readonly MYSQL_QUERY: "orchestrion:mysql:query"; | ||
| }; | ||
| //# sourceMappingURL=mysql.d.ts.map |
| {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/mysql.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,WAAW;;;;;;;;;;;GAMW,CAAC;AAEpC,eAAO,MAAM,aAAa;;CAEhB,CAAC"} |
| export declare const openaiConfig: { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| }; | ||
| }[]; | ||
| export declare const openaiChannels: { | ||
| readonly OPENAI_CHAT: "orchestrion:openai:chat"; | ||
| readonly OPENAI_RESPONSES: "orchestrion:openai:responses"; | ||
| readonly OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings"; | ||
| readonly OPENAI_CONVERSATIONS: "orchestrion:openai:conversations"; | ||
| }; | ||
| //# sourceMappingURL=openai.d.ts.map |
| {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/openai.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,YAAY;;;;;;;;;;;;GA2BU,CAAC;AAEpC,eAAO,MAAM,cAAc;;;;;CAKjB,CAAC"} |
| export declare const pgConfig: ({ | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| className: string; | ||
| methodName: string; | ||
| kind: "Auto"; | ||
| expressionName?: undefined; | ||
| }; | ||
| } | { | ||
| channelName: string; | ||
| module: { | ||
| name: string; | ||
| versionRange: string; | ||
| filePath: string; | ||
| }; | ||
| functionQuery: { | ||
| expressionName: string; | ||
| kind: "Auto"; | ||
| className?: undefined; | ||
| methodName?: undefined; | ||
| }; | ||
| })[]; | ||
| export declare const pgChannels: { | ||
| readonly PG_QUERY: "orchestrion:pg:query"; | ||
| readonly PG_CONNECT: "orchestrion:pg:connect"; | ||
| readonly PGPOOL_CONNECT: "orchestrion:pg-pool:connect"; | ||
| }; | ||
| //# sourceMappingURL=pg.d.ts.map |
| {"version":3,"file":"pg.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/pg.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;IAuCc,CAAC;AAEpC,eAAO,MAAM,UAAU;;;;CAIb,CAAC"} |
| import type { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| export declare const vercelAiConfig: InstrumentationConfig[]; | ||
| export declare const vercelAiChannels: { | ||
| readonly VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText"; | ||
| readonly VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText"; | ||
| readonly VERCEL_AI_EMBED: "orchestrion:ai:embed"; | ||
| readonly VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany"; | ||
| readonly VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall"; | ||
| readonly VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel"; | ||
| }; | ||
| //# sourceMappingURL=vercel-ai.d.ts.map |
| {"version":3,"file":"vercel-ai.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/config/vercel-ai.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E,eAAO,MAAM,cAAc,yBAeQ,CAAC;AAEpC,eAAO,MAAM,gBAAgB;;;;;;;CAcnB,CAAC"} |
| /** | ||
| * Given the redis command name and arguments, return a combination of the | ||
| * command name + the allowed arguments according to `serializationSubsets`. | ||
| */ | ||
| export declare const defaultDbStatementSerializer: (cmdName: string, cmdArgs: Array<string | Buffer | number | unknown[]>) => string; | ||
| //# sourceMappingURL=redis-statement-serializer.d.ts.map |
| {"version":3,"file":"redis-statement-serializer.d.ts","sourceRoot":"","sources":["../../../src/redis/redis-statement-serializer.ts"],"names":[],"mappings":"AA0CA;;;GAGG;AACH,eAAO,MAAM,4BAA4B,GACvC,SAAS,MAAM,EACf,SAAS,KAAK,CAAC,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,EAAE,CAAC,KACnD,MAWF,CAAC"} |
| import { type VercelAiChannelOptions, type VercelAiTracingChannelFactory } from './vercel-ai-dc-subscriber'; | ||
| /** | ||
| * Subscribe the v6 orchestrion channel adapter. Safe to always call: inert on | ||
| * `ai` >= 7 (those channels are never published) and when orchestrion injection | ||
| * isn't active. Idempotent. | ||
| * | ||
| * `tracingChannel` is the platform-provided factory (the same one passed to | ||
| * `subscribeVercelAiTracingChannel`); `options` pins the recording settings at | ||
| * subscribe time so we never look the integration up per event. | ||
| */ | ||
| export declare function subscribeVercelAiOrchestrionChannels(tracingChannel: VercelAiTracingChannelFactory, options?: VercelAiChannelOptions): void; | ||
| //# sourceMappingURL=vercel-ai-orchestrion-v6-subscriber.d.ts.map |
| {"version":3,"file":"vercel-ai-orchestrion-v6-subscriber.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/vercel-ai-orchestrion-v6-subscriber.ts"],"names":[],"mappings":"AAKA,OAAO,EAML,KAAK,sBAAsB,EAC3B,KAAK,6BAA6B,EACnC,MAAM,2BAA2B,CAAC;AAyEnC;;;;;;;;GAQG;AACH,wBAAgB,oCAAoC,CAClD,cAAc,EAAE,6BAA6B,EAC7C,OAAO,GAAE,sBAA2B,GACnC,IAAI,CA6DN"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const index$1 = require('./mongoose/index.js'); | ||
| const redisDcSubscriber = require('./redis/redis-dc-subscriber.js'); | ||
| const redisStatementSerializer = require('./redis/redis-statement-serializer.js'); | ||
| const tracingChannel = require('./tracing-channel.js'); | ||
| const index$1 = require('./vercel-ai/index.js'); | ||
| const index$2 = require('./vercel-ai/index.js'); | ||
| const index = require('./integrations/tracing-channel/fastify/index.js'); | ||
@@ -10,2 +12,3 @@ | ||
| exports.mongooseIntegration = index$1.mongooseIntegration; | ||
| exports.IOREDIS_DC_CHANNEL_COMMAND = redisDcSubscriber.IOREDIS_DC_CHANNEL_COMMAND; | ||
@@ -17,4 +20,5 @@ exports.IOREDIS_DC_CHANNEL_CONNECT = redisDcSubscriber.IOREDIS_DC_CHANNEL_CONNECT; | ||
| exports.subscribeRedisDiagnosticChannels = redisDcSubscriber.subscribeRedisDiagnosticChannels; | ||
| exports.defaultDbStatementSerializer = redisStatementSerializer.defaultDbStatementSerializer; | ||
| exports.bindTracingChannelToSpan = tracingChannel.bindTracingChannelToSpan; | ||
| exports.vercelAiIntegration = index$1.vercelAiIntegration; | ||
| exports.vercelAiIntegration = index$2.vercelAiIntegration; | ||
| exports.fastifyIntegration = index.fastifyIntegration; | ||
@@ -21,0 +25,0 @@ exports.handleFastifyError = index.handleFastifyError; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;"} |
@@ -36,2 +36,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| name: sql ?? "mysql.query", | ||
| kind: core.SPAN_KIND.CLIENT, | ||
| op: "db", | ||
@@ -38,0 +39,0 @@ attributes: { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql' as const;\n\n// OTel \"OLD\" db/net semantic-conventions, inlined to keep this integration free of OTel deps. Matches\n// `@opentelemetry/instrumentation-mysql`'s default and the SDK's `inferDbSpanData` (which renames spans\n// off `db.statement`).\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context` object. Documented here\n * rather than imported because orchestrion's runtime doesn't export it.\n */\ninterface MysqlQueryChannelContext {\n // The live args array passed to the wrapped `connection.query` call; `arguments[0]` is the SQL.\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto the streamed `Query` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<MysqlQueryChannelContext>(CHANNELS.MYSQL_QUERY),\n data => {\n const sql = extractSql(data.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(data.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n // For the streamed path: mysql emits the `Query` emitter's events from its socket data\n // handler with the caller's context lost. `deferSpanEnd` replays this scope onto the emitter.\n data._sentryCallerScope = getCurrentScope();\n\n return startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n },\n {\n // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the\n // emitter's `'end'`/`'error'`, not the channel, so defer ending to those.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope so user listeners on the emitter nest under it, not a new trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n },\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","waitForTracingChannelBinding","bindTracingChannelToSpan","getCurrentScope","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","bindScopeToEmitter","defineIntegration"],"mappings":";;;;;;;;AAiBA,MAAM,gBAAA,GAAmB,OAAA;AAKzB,MAAM,cAAA,GAAiB,WAAA;AACvB,MAAM,yBAAA,GAA4B,sBAAA;AAClC,MAAM,YAAA,GAAe,SAAA;AACrB,MAAM,YAAA,GAAe,SAAA;AACrB,MAAM,iBAAA,GAAoB,cAAA;AAC1B,MAAM,kBAAA,GAAqB,eAAA;AAC3B,MAAM,kBAAA,GAAqB,eAAA;AA8B3B,MAAM,4BAA4B,MAAM;AACtC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,mBAAmB,cAAA,EAAgB;AACtC,QAAA;AAAA,MACF;AAEA,MAAAA,sBAAA,IAAeC,UAAA,CAAM,GAAA,CAAI,CAAA,4CAAA,EAA+CC,iBAAA,CAAS,WAAW,CAAA,CAAA,CAAG,CAAA;AAE/F,MAAAC,iCAAA,CAA6B,MAAM;AACjC,QAAAC,uCAAA;AAAA,UACE,kBAAA,CAAmB,cAAA,CAAyCF,iBAAA,CAAS,WAAW,CAAA;AAAA,UAChF,CAAA,IAAA,KAAQ;AACN,YAAA,MAAM,GAAA,GAAM,UAAA,CAAW,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AACxC,YAAA,MAAM,EAAE,MAAM,IAAA,EAAM,QAAA,EAAU,MAAK,GAAI,mBAAA,CAAoB,KAAK,IAAI,CAAA;AACpE,YAAA,MAAM,aAAa,OAAO,IAAA,KAAS,WAAW,QAAA,CAAS,IAAA,EAAM,EAAE,CAAA,GAAI,IAAA;AACnE,YAAA,MAAM,eAAe,OAAO,UAAA,KAAe,QAAA,IAAY,CAAC,MAAM,UAAU,CAAA;AAIxE,YAAA,IAAA,CAAK,qBAAqBG,oBAAA,EAAgB;AAE1C,YAAA,OAAOC,sBAAA,CAAkB;AAAA,cACvB,MAAM,GAAA,IAAO,aAAA;AAAA,cACb,EAAA,EAAI,IAAA;AAAA,cACJ,UAAA,EAAY;AAAA,gBACV,CAAC,cAAc,GAAG,OAAA;AAAA,gBAClB,CAACC,qCAAgC,GAAG,2BAAA;AAAA,gBACpC,CAAC,yBAAyB,GAAG,aAAA,CAAc,MAAM,YAAA,GAAe,UAAA,GAAa,QAAW,QAAQ,CAAA;AAAA,gBAChG,GAAI,WAAW,EAAE,CAAC,YAAY,GAAG,QAAA,KAAa,EAAC;AAAA,gBAC/C,GAAI,OAAO,EAAE,CAAC,YAAY,GAAG,IAAA,KAAS,EAAC;AAAA,gBACvC,GAAI,MAAM,EAAE,CAAC,iBAAiB,GAAG,GAAA,KAAQ,EAAC;AAAA,gBAC1C,GAAI,OAAO,EAAE,CAAC,kBAAkB,GAAG,IAAA,KAAS,EAAC;AAAA,gBAC7C,GAAI,eAAe,EAAE,CAAC,kBAAkB,GAAG,UAAA,KAAe;AAAC;AAC7D,aACD,CAAA;AAAA,UACH,CAAA;AAAA,UACA;AAAA;AAAA;AAAA,YAGE,YAAA,CAAa,EAAE,IAAA,EAAM,GAAA,EAAI,EAAG;AAC1B,cAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,cAAA,IAAI,CAAC,UAAU,OAAO,MAAA,KAAW,YAAY,CAAC,WAAA,CAAY,MAAM,CAAA,EAAG;AACjE,gBAAA,OAAO,KAAA;AAAA,cACT;AAGA,cAAA,MAAM,cAAc,IAAA,CAAK,kBAAA;AACzB,cAAA,IAAI,WAAA,EAAa;AACf,gBAAAC,uBAAA,CAAmB,QAAQ,WAAW,CAAA;AAAA,cACxC;AAEA,cAAA,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAA,GAAA,KAAO,GAAA,CAAI,GAAG,CAAC,CAAA;AAClC,cAAA,MAAA,CAAO,EAAA,CAAG,KAAA,EAAO,MAAM,GAAA,EAAK,CAAA;AAE5B,cAAA,OAAO,IAAA;AAAA,YACT;AAAA;AACF,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAEA,SAAS,YAAY,GAAA,EAA2F;AAC9G,EAAA,OAAO,IAAA,IAAQ,GAAA,IAAO,OAAQ,GAAA,CAAyB,EAAA,KAAO,UAAA;AAChE;AAEA,SAAS,WAAW,QAAA,EAAuC;AACzD,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,IAAY,SAAS,QAAA,EAAU;AACjE,IAAA,MAAM,MAAO,QAAA,CAA+B,GAAA;AAC5C,IAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,GAAW,GAAA,GAAM,MAAA;AAAA,EACzC;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,oBAAoB,UAAA,EAK3B;AAGA,EAAA,MAAM,SAAS,UAAA,EAAY,MAAA,EAAQ,gBAAA,IAAoB,UAAA,EAAY,UAAU,EAAC;AAC9E,EAAA,OAAO;AAAA,IACL,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,MAAM,MAAA,CAAO;AAAA,GACf;AACF;AAEA,SAAS,aAAA,CAAc,IAAA,EAA0B,IAAA,EAA0B,QAAA,EAAsC;AAC/G,EAAA,IAAI,CAAA,GAAI,CAAA,aAAA,EAAgB,IAAA,IAAQ,WAAW,CAAA,CAAA;AAC3C,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,CAAA,IAAK,IAAI,IAAI,CAAA,CAAA;AAAA,EACf;AACA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,CAAA,IAAK,IAAI,QAAQ,CAAA,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,CAAA;AACT;AAUO,MAAM,uBAAA,GAA0BC,uBAAkB,wBAAwB;;;;"} | ||
| {"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_KIND,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql' as const;\n\n// OTel \"OLD\" db/net semantic-conventions, inlined to keep this integration free of OTel deps. Matches\n// `@opentelemetry/instrumentation-mysql`'s default and the SDK's `inferDbSpanData` (which renames spans\n// off `db.statement`).\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context` object. Documented here\n * rather than imported because orchestrion's runtime doesn't export it.\n */\ninterface MysqlQueryChannelContext {\n // The live args array passed to the wrapped `connection.query` call; `arguments[0]` is the SQL.\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto the streamed `Query` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<MysqlQueryChannelContext>(CHANNELS.MYSQL_QUERY),\n data => {\n const sql = extractSql(data.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(data.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n // For the streamed path: mysql emits the `Query` emitter's events from its socket data\n // handler with the caller's context lost. `deferSpanEnd` replays this scope onto the emitter.\n data._sentryCallerScope = getCurrentScope();\n\n return startInactiveSpan({\n name: sql ?? 'mysql.query',\n kind: SPAN_KIND.CLIENT,\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n },\n {\n // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the\n // emitter's `'end'`/`'error'`, not the channel, so defer ending to those.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope so user listeners on the emitter nest under it, not a new trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n },\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","waitForTracingChannelBinding","bindTracingChannelToSpan","getCurrentScope","startInactiveSpan","SPAN_KIND","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","bindScopeToEmitter","defineIntegration"],"mappings":"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"} |
@@ -5,6 +5,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const MagicString = require('magic-string'); | ||
| const config = require('../config.js'); | ||
| const index = require('../config/index.js'); | ||
| function sentryOrchestrionPlugin() { | ||
| const codeTransformerPlugins = codeTransformer.default({ instrumentations: config.SENTRY_INSTRUMENTATIONS }); | ||
| const codeTransformerPlugins = codeTransformer.default({ instrumentations: index.SENTRY_INSTRUMENTATIONS }); | ||
| const codeTransformerArray = Array.isArray(codeTransformerPlugins) ? codeTransformerPlugins : [codeTransformerPlugins]; | ||
@@ -23,3 +23,3 @@ return [bundlerMarkerPlugin(), ...codeTransformerArray]; | ||
| config() { | ||
| return { ssr: { noExternal: config.INSTRUMENTED_MODULE_NAMES } }; | ||
| return { ssr: { noExternal: index.INSTRUMENTED_MODULE_NAMES } }; | ||
| }, | ||
@@ -26,0 +26,0 @@ renderChunk(code, chunk) { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"vite.js","sources":["../../../../src/orchestrion/bundler/vite.ts"],"sourcesContent":["// EXPERIMENTAL — Vite plugin that runs the orchestrion code transform at build\n// time, injecting `diagnostics_channel.tracingChannel` calls into the libraries\n// listed in `SENTRY_INSTRUMENTATIONS`.\n//\n// This file is published ESM-only via the `@sentry/server-utils/orchestrion/vite`\n// subpath export. `@apm-js-collab/code-transformer-bundler-plugins` is\n// `\"type\": \"module\"`, so consuming it from a CJS build is intentionally\n// unsupported — vite.config.ts is almost always ESM in practice. The CJS\n// rollup variant still emits this file, but `package.json` only exposes the\n// ESM entry, so attempts to `require('@sentry/server-utils/orchestrion/vite')` will\n// fail at resolution time rather than producing a half-broken plugin.\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype UnknownPlugin = any;\n\nimport codeTransformer from '@apm-js-collab/code-transformer-bundler-plugins/vite';\nimport MagicString from 'magic-string';\nimport { INSTRUMENTED_MODULE_NAMES, SENTRY_INSTRUMENTATIONS } from '../config';\n\n// `vite` types live in the package's ESM-only subpath; under Node16 module\n// resolution with TS treating @sentry/server-utils as CJS, importing them produces a\n// false positive. We don't need the runtime value for typing — `UnknownPlugin`\n// is sufficient — so we omit the import entirely.\n\n/**\n * Vite plugin that runs the orchestrion code transform on the bundled output.\n *\n * Use when bundling a Node app with Vite (e.g. Vite SSR builds, Nuxt's Nitro\n * pipeline, SvelteKit). For unbundled Node processes use the runtime hook\n * instead (`node --import @sentry/node/orchestrion app.js`).\n *\n * Returns two plugins:\n * 1. `sentry-orchestrion-marker` — a `renderChunk` hook that prepends a\n * single-line banner to entry chunks. The banner sets\n * `globalThis.__SENTRY_ORCHESTRION__.bundler = true` at app boot, so the\n * `_experimentalSetupOrchestrion()` detector can confirm the bundler path\n * ran (rather than relying on a build-time flag that wouldn't be visible\n * to the runtime).\n * Also injects every instrumented package name into `ssr.noExternal` via\n * the `config` hook, since externalized deps are `require()`d at runtime\n * from `node_modules` and never pass through the transform.\n * 2. The upstream `@apm-js-collab/code-transformer-bundler-plugins/vite`\n * plugin, fed our central `SENTRY_INSTRUMENTATIONS` config.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { sentryOrchestrionPlugin } from '@sentry/node/orchestrion/vite';\n * export default { plugins: [sentryOrchestrionPlugin()] };\n * ```\n */\nexport function sentryOrchestrionPlugin(): UnknownPlugin[] {\n const codeTransformerPlugins = codeTransformer({ instrumentations: SENTRY_INSTRUMENTATIONS });\n const codeTransformerArray: UnknownPlugin[] = Array.isArray(codeTransformerPlugins)\n ? codeTransformerPlugins\n : [codeTransformerPlugins];\n return [bundlerMarkerPlugin(), ...codeTransformerArray];\n}\n\nfunction bundlerMarkerPlugin(): UnknownPlugin {\n const banner = [\n 'globalThis.__SENTRY_ORCHESTRION__ = (globalThis.__SENTRY_ORCHESTRION__ || {});',\n 'globalThis.__SENTRY_ORCHESTRION__.bundler = true;',\n '',\n ].join('\\n');\n\n return {\n name: 'sentry-orchestrion-marker',\n enforce: 'pre' as const,\n config(): { ssr: { noExternal: string[] } } {\n // Force-bundle every instrumented package so the code transform actually\n // sees its source. Vite externalizes dependencies in SSR builds by\n // default, leaving them as bare `require()`/`import` calls resolved from\n // `node_modules` at runtime — those copies are untouched and the\n // diagnostics_channel calls never get injected. Vite merges array\n // `noExternal` entries with the user's config, so we don't overwrite\n // their additions.\n return { ssr: { noExternal: INSTRUMENTED_MODULE_NAMES } };\n },\n renderChunk(code: string, chunk: { isEntry: boolean }): { code: string; map: unknown } | null {\n if (!chunk.isEntry) return null;\n // Prepend via magic-string so the entry chunk's sourcemap stays aligned —\n // returning `map: null` here would shift every mapping by the banner's\n // line count and misattribute server stack traces.\n const ms = new MagicString(code);\n ms.prepend(banner);\n return { code: ms.toString(), map: ms.generateMap({ hires: true }) };\n },\n };\n}\n"],"names":["codeTransformer","SENTRY_INSTRUMENTATIONS","INSTRUMENTED_MODULE_NAMES","MagicString"],"mappings":";;;;;;AAmDO,SAAS,uBAAA,GAA2C;AACzD,EAAA,MAAM,sBAAA,GAAyBA,uBAAA,CAAgB,EAAE,gBAAA,EAAkBC,gCAAyB,CAAA;AAC5F,EAAA,MAAM,uBAAwC,KAAA,CAAM,OAAA,CAAQ,sBAAsB,CAAA,GAC9E,sBAAA,GACA,CAAC,sBAAsB,CAAA;AAC3B,EAAA,OAAO,CAAC,mBAAA,EAAoB,EAAG,GAAG,oBAAoB,CAAA;AACxD;AAEA,SAAS,mBAAA,GAAqC;AAC5C,EAAA,MAAM,MAAA,GAAS;AAAA,IACb,gFAAA;AAAA,IACA,mDAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AAEX,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,2BAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT,MAAA,GAA4C;AAQ1C,MAAA,OAAO,EAAE,GAAA,EAAK,EAAE,UAAA,EAAYC,kCAA0B,EAAE;AAAA,IAC1D,CAAA;AAAA,IACA,WAAA,CAAY,MAAc,KAAA,EAAoE;AAC5F,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,IAAA;AAI3B,MAAA,MAAM,EAAA,GAAK,IAAIC,mBAAA,CAAY,IAAI,CAAA;AAC/B,MAAA,EAAA,CAAG,QAAQ,MAAM,CAAA;AACjB,MAAA,OAAO,EAAE,IAAA,EAAM,EAAA,CAAG,QAAA,EAAS,EAAG,GAAA,EAAK,EAAA,CAAG,WAAA,CAAY,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,IACrE;AAAA,GACF;AACF;;;;"} | ||
| {"version":3,"file":"vite.js","sources":["../../../../src/orchestrion/bundler/vite.ts"],"sourcesContent":["// EXPERIMENTAL — Vite plugin that runs the orchestrion code transform at build\n// time, injecting `diagnostics_channel.tracingChannel` calls into the libraries\n// listed in `SENTRY_INSTRUMENTATIONS`.\n//\n// This file is published ESM-only via the `@sentry/server-utils/orchestrion/vite`\n// subpath export. `@apm-js-collab/code-transformer-bundler-plugins` is\n// `\"type\": \"module\"`, so consuming it from a CJS build is intentionally\n// unsupported — vite.config.ts is almost always ESM in practice. The CJS\n// rollup variant still emits this file, but `package.json` only exposes the\n// ESM entry, so attempts to `require('@sentry/server-utils/orchestrion/vite')` will\n// fail at resolution time rather than producing a half-broken plugin.\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype UnknownPlugin = any;\n\nimport codeTransformer from '@apm-js-collab/code-transformer-bundler-plugins/vite';\nimport MagicString from 'magic-string';\nimport { INSTRUMENTED_MODULE_NAMES, SENTRY_INSTRUMENTATIONS } from '../config';\n\n// `vite` types live in the package's ESM-only subpath; under Node16 module\n// resolution with TS treating @sentry/server-utils as CJS, importing them produces a\n// false positive. We don't need the runtime value for typing — `UnknownPlugin`\n// is sufficient — so we omit the import entirely.\n\n/**\n * Vite plugin that runs the orchestrion code transform on the bundled output.\n *\n * Use when bundling a Node app with Vite (e.g. Vite SSR builds, Nuxt's Nitro\n * pipeline, SvelteKit). For unbundled Node processes use the runtime hook\n * instead (`node --import @sentry/node/orchestrion app.js`).\n *\n * Returns two plugins:\n * 1. `sentry-orchestrion-marker` — a `renderChunk` hook that prepends a\n * single-line banner to entry chunks. The banner sets\n * `globalThis.__SENTRY_ORCHESTRION__.bundler = true` at app boot, so the\n * `_experimentalSetupOrchestrion()` detector can confirm the bundler path\n * ran (rather than relying on a build-time flag that wouldn't be visible\n * to the runtime).\n * Also injects every instrumented package name into `ssr.noExternal` via\n * the `config` hook, since externalized deps are `require()`d at runtime\n * from `node_modules` and never pass through the transform.\n * 2. The upstream `@apm-js-collab/code-transformer-bundler-plugins/vite`\n * plugin, fed our central `SENTRY_INSTRUMENTATIONS` config.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { sentryOrchestrionPlugin } from '@sentry/node/orchestrion/vite';\n * export default { plugins: [sentryOrchestrionPlugin()] };\n * ```\n */\nexport function sentryOrchestrionPlugin(): UnknownPlugin[] {\n const codeTransformerPlugins = codeTransformer({ instrumentations: SENTRY_INSTRUMENTATIONS });\n const codeTransformerArray: UnknownPlugin[] = Array.isArray(codeTransformerPlugins)\n ? codeTransformerPlugins\n : [codeTransformerPlugins];\n return [bundlerMarkerPlugin(), ...codeTransformerArray];\n}\n\nfunction bundlerMarkerPlugin(): UnknownPlugin {\n const banner = [\n 'globalThis.__SENTRY_ORCHESTRION__ = (globalThis.__SENTRY_ORCHESTRION__ || {});',\n 'globalThis.__SENTRY_ORCHESTRION__.bundler = true;',\n '',\n ].join('\\n');\n\n return {\n name: 'sentry-orchestrion-marker',\n enforce: 'pre' as const,\n config(): { ssr: { noExternal: string[] } } {\n // Force-bundle every instrumented package so the code transform actually\n // sees its source. Vite externalizes dependencies in SSR builds by\n // default, leaving them as bare `require()`/`import` calls resolved from\n // `node_modules` at runtime — those copies are untouched and the\n // diagnostics_channel calls never get injected. Vite merges array\n // `noExternal` entries with the user's config, so we don't overwrite\n // their additions.\n return { ssr: { noExternal: INSTRUMENTED_MODULE_NAMES } };\n },\n renderChunk(code: string, chunk: { isEntry: boolean }): { code: string; map: unknown } | null {\n if (!chunk.isEntry) return null;\n // Prepend via magic-string so the entry chunk's sourcemap stays aligned —\n // returning `map: null` here would shift every mapping by the banner's\n // line count and misattribute server stack traces.\n const ms = new MagicString(code);\n ms.prepend(banner);\n return { code: ms.toString(), map: ms.generateMap({ hires: true }) };\n },\n };\n}\n"],"names":["codeTransformer","SENTRY_INSTRUMENTATIONS","INSTRUMENTED_MODULE_NAMES","MagicString"],"mappings":";;;;;;AAmDO,SAAS,uBAAA,GAA2C;AACzD,EAAA,MAAM,sBAAA,GAAyBA,uBAAA,CAAgB,EAAE,gBAAA,EAAkBC,+BAAyB,CAAA;AAC5F,EAAA,MAAM,uBAAwC,KAAA,CAAM,OAAA,CAAQ,sBAAsB,CAAA,GAC9E,sBAAA,GACA,CAAC,sBAAsB,CAAA;AAC3B,EAAA,OAAO,CAAC,mBAAA,EAAoB,EAAG,GAAG,oBAAoB,CAAA;AACxD;AAEA,SAAS,mBAAA,GAAqC;AAC5C,EAAA,MAAM,MAAA,GAAS;AAAA,IACb,gFAAA;AAAA,IACA,mDAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,IAAI,CAAA;AAEX,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,2BAAA;AAAA,IACN,OAAA,EAAS,KAAA;AAAA,IACT,MAAA,GAA4C;AAQ1C,MAAA,OAAO,EAAE,GAAA,EAAK,EAAE,UAAA,EAAYC,iCAA0B,EAAE;AAAA,IAC1D,CAAA;AAAA,IACA,WAAA,CAAY,MAAc,KAAA,EAAoE;AAC5F,MAAA,IAAI,CAAC,KAAA,CAAM,OAAA,EAAS,OAAO,IAAA;AAI3B,MAAA,MAAM,EAAA,GAAK,IAAIC,mBAAA,CAAY,IAAI,CAAA;AAC/B,MAAA,EAAA,CAAG,QAAQ,MAAM,CAAA;AACjB,MAAA,OAAO,EAAE,IAAA,EAAM,EAAA,CAAG,QAAA,EAAS,EAAG,GAAA,EAAK,EAAA,CAAG,WAAA,CAAY,EAAE,KAAA,EAAO,IAAA,EAAM,CAAA,EAAE;AAAA,IACrE;AAAA,GACF;AACF;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const mysql = require('./config/mysql.js'); | ||
| const lruMemoizer = require('./config/lru-memoizer.js'); | ||
| const ioredis = require('./config/ioredis.js'); | ||
| const pg = require('./config/pg.js'); | ||
| const openai = require('./config/openai.js'); | ||
| const anthropicAi = require('./config/anthropic-ai.js'); | ||
| const vercelAi = require('./config/vercel-ai.js'); | ||
| const hapi = require('./config/hapi.js'); | ||
| const CHANNELS = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query", | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| ...mysql.mysqlChannels, | ||
| ...lruMemoizer.lruMemoizerChannels, | ||
| ...ioredis.ioredisChannels, | ||
| ...pg.pgChannels, | ||
| ...openai.openaiChannels, | ||
| ...anthropicAi.anthropicAiChannels, | ||
| ...vercelAi.vercelAiChannels, | ||
| ...hapi.hapiChannels | ||
| }; | ||
@@ -7,0 +22,0 @@ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"channels.js","sources":["../../../src/orchestrion/channels.ts"],"sourcesContent":["/**\n * Fully-qualified `diagnostics_channel` names that orchestrion publishes to.\n *\n * Orchestrion's transform always prefixes the configured `channelName` with\n * `orchestrion:${module.name}:`. So a config of\n * `{ channelName: 'query', module: { name: 'mysql' } }`\n * publishes to `orchestrion:mysql:query`.\n *\n * Subscribers (`integrations/<lib>/tracing-channel.ts`) consume the full\n * prefixed string from this map; the config files set only the unprefixed\n * suffix in `channelName`. Keeping both pieces in one file is what guarantees\n * they don't drift apart and silently stop firing.\n */\nexport const CHANNELS = {\n MYSQL_QUERY: 'orchestrion:mysql:query',\n LRU_MEMOIZER_LOAD: 'orchestrion:lru-memoizer:load',\n} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":[],"mappings":";;AAaO,MAAM,QAAA,GAAW;AAAA,EACtB,WAAA,EAAa,yBAAA;AAAA,EACb,iBAAA,EAAmB;AACrB;;;;"} | ||
| {"version":3,"file":"channels.js","sources":["../../../src/orchestrion/channels.ts"],"sourcesContent":["import { mysqlChannels } from './config/mysql';\nimport { lruMemoizerChannels } from './config/lru-memoizer';\nimport { ioredisChannels } from './config/ioredis';\nimport { pgChannels } from './config/pg';\nimport { openaiChannels } from './config/openai';\nimport { anthropicAiChannels } from './config/anthropic-ai';\nimport { vercelAiChannels } from './config/vercel-ai';\nimport { hapiChannels } from './config/hapi';\n\n/**\n * Fully-qualified `diagnostics_channel` names that orchestrion publishes to.\n *\n * Orchestrion's transform always prefixes the configured `channelName` with\n * `orchestrion:${module.name}:`. So a config of\n * `{ channelName: 'query', module: { name: 'mysql' } }`\n * publishes to `orchestrion:mysql:query`.\n *\n * Subscribers (`integrations/<lib>/tracing-channel.ts`) consume the full\n * prefixed string from this map; the config files set only the unprefixed\n * suffix in `channelName`. Keeping both pieces in one file is what guarantees\n * they don't drift apart and silently stop firing.\n */\nexport const CHANNELS = {\n ...mysqlChannels,\n ...lruMemoizerChannels,\n ...ioredisChannels,\n ...pgChannels,\n ...openaiChannels,\n ...anthropicAiChannels,\n ...vercelAiChannels,\n ...hapiChannels,\n} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":["mysqlChannels","lruMemoizerChannels","ioredisChannels","pgChannels","openaiChannels","anthropicAiChannels","vercelAiChannels","hapiChannels"],"mappings":";;;;;;;;;;;AAsBO,MAAM,QAAA,GAAW;AAAA,EACtB,GAAGA,mBAAA;AAAA,EACH,GAAGC,+BAAA;AAAA,EACH,GAAGC,uBAAA;AAAA,EACH,GAAGC,aAAA;AAAA,EACH,GAAGC,qBAAA;AAAA,EACH,GAAGC,+BAAA;AAAA,EACH,GAAGC,yBAAA;AAAA,EACH,GAAGC;AACL;;;;"} |
@@ -6,2 +6,6 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| function isOrchestrionInjected() { | ||
| const marker = globalThis.__SENTRY_ORCHESTRION__; | ||
| return !!(marker?.runtime || marker?.bundler); | ||
| } | ||
| function detectOrchestrionSetup() { | ||
@@ -13,3 +17,3 @@ if (!debugBuild.DEBUG_BUILD) return; | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`); | ||
| if (!runtime && !bundler) { | ||
| if (!isOrchestrionInjected()) { | ||
| debugBuild.DEBUG_BUILD && core.debug.warn( | ||
@@ -22,2 +26,3 @@ "[Sentry] No diagnostics-channel injection detected. Channel-based integrations (mysql, \u2026) will not record spans. Make sure the diagnostics channels are injected via the runtime `--import` hook or a bundler plugin before the instrumented modules load." | ||
| exports.detectOrchestrionSetup = detectOrchestrionSetup; | ||
| exports.isOrchestrionInjected = isOrchestrionInjected; | ||
| //# sourceMappingURL=detect.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"detect.js","sources":["../../../src/orchestrion/detect.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Verifies that the diagnostics channels have been injected either by the\n * runtime `--import` hook (or init-time registration), a bundler plugin, or\n * both, and warns if not.\n *\n * Both injectors being active at once is fine: they operate on disjoint module\n * sets (a module is either loaded through Node's loader and transformed by the\n * runtime hook, or inlined by the bundler and transformed by the plugin), so\n * a single module can't be double-wrapped. A hybrid setup, with some deps\n * external and runtime-instrumented, others bundled and plugin-instrumented,\n * is fine.\n *\n * Note: intentionally does NOT warn in production, only in debug builds,\n * because production warnings are reserved for truly critical issues.\n */\nexport function detectOrchestrionSetup(): void {\n if (!DEBUG_BUILD) return;\n\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n const runtime = !!marker?.runtime;\n const bundler = !!marker?.bundler;\n\n DEBUG_BUILD && debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`);\n\n if (!runtime && !bundler) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] No diagnostics-channel injection detected. Channel-based integrations ' +\n '(mysql, …) will not record spans. Make sure the diagnostics channels are injected ' +\n 'via the runtime `--import` hook or a bundler plugin before the instrumented modules load.',\n );\n }\n}\n"],"names":["DEBUG_BUILD","debug"],"mappings":";;;;;AAuBO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,CAACA,sBAAA,EAAa;AAElB,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAE1B,EAAAA,sBAAA,IAAeC,WAAM,GAAA,CAAI,CAAA,8BAAA,EAAiC,OAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAEtF,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AACxB,IAAAD,sBAAA,IACEC,UAAA,CAAM,IAAA;AAAA,MACJ;AAAA,KAGF;AAAA,EACJ;AACF;;;;"} | ||
| {"version":3,"file":"detect.js","sources":["../../../src/orchestrion/detect.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Whether orchestrion has injected the diagnostics channels into this process,\n * either by the runtime `--import` hook / init-time registration (`runtime`)\n * or a bundler plugin (`bundler`). Both injectors set a flag on the\n * `globalThis.__SENTRY_ORCHESTRION__` marker.\n *\n * Use this to avoid wiring up channel-subscriber integrations when nothing\n * will ever publish to those channels.\n */\nexport function isOrchestrionInjected(): boolean {\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n return !!(marker?.runtime || marker?.bundler);\n}\n\n/**\n * Verifies that the diagnostics channels have been injected either by the\n * runtime `--import` hook (or init-time registration), a bundler plugin, or\n * both, and warns if not.\n *\n * Both injectors being active at once is fine: they operate on disjoint module\n * sets (a module is either loaded through Node's loader and transformed by the\n * runtime hook, or inlined by the bundler and transformed by the plugin), so\n * a single module can't be double-wrapped. A hybrid setup, with some deps\n * external and runtime-instrumented, others bundled and plugin-instrumented,\n * is fine.\n *\n * Note: intentionally does NOT warn in production, only in debug builds,\n * because production warnings are reserved for truly critical issues.\n */\nexport function detectOrchestrionSetup(): void {\n if (!DEBUG_BUILD) return;\n\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n const runtime = !!marker?.runtime;\n const bundler = !!marker?.bundler;\n\n DEBUG_BUILD && debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`);\n\n if (!isOrchestrionInjected()) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] No diagnostics-channel injection detected. Channel-based integrations ' +\n '(mysql, …) will not record spans. Make sure the diagnostics channels are injected ' +\n 'via the runtime `--import` hook or a bundler plugin before the instrumented modules load.',\n );\n }\n}\n"],"names":["DEBUG_BUILD","debug"],"mappings":";;;;;AAiBO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,OAAO,CAAC,EAAE,MAAA,EAAQ,OAAA,IAAW,MAAA,EAAQ,OAAA,CAAA;AACvC;AAiBO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,CAACA,sBAAA,EAAa;AAElB,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAE1B,EAAAA,sBAAA,IAAeC,WAAM,GAAA,CAAI,CAAA,8BAAA,EAAiC,OAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAEtF,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC5B,IAAAD,sBAAA,IACEC,UAAA,CAAM,IAAA;AAAA,MACJ;AAAA,KAGF;AAAA,EACJ;AACF;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const anthropic = require('../integrations/tracing-channel/anthropic.js'); | ||
| const hapi = require('../integrations/tracing-channel/hapi.js'); | ||
| const ioredis = require('../integrations/tracing-channel/ioredis.js'); | ||
| const lruMemoizer = require('../integrations/tracing-channel/lru-memoizer.js'); | ||
| const mysql = require('../integrations/tracing-channel/mysql.js'); | ||
| const openai = require('../integrations/tracing-channel/openai.js'); | ||
| const postgres = require('../integrations/tracing-channel/postgres.js'); | ||
| const vercelAi = require('../integrations/tracing-channel/vercel-ai.js'); | ||
| const detect = require('./detect.js'); | ||
| const mysql = require('../integrations/tracing-channel/mysql.js'); | ||
| const lruMemoizer = require('../integrations/tracing-channel/lru-memoizer.js'); | ||
| const channelIntegrations = { | ||
| postgresIntegration: postgres.postgresChannelIntegration, | ||
| mysqlIntegration: mysql.mysqlChannelIntegration, | ||
| lruMemoizerIntegration: lruMemoizer.lruMemoizerChannelIntegration, | ||
| openaiIntegration: openai.openaiChannelIntegration, | ||
| anthropicIntegration: anthropic.anthropicChannelIntegration, | ||
| vercelAiIntegration: vercelAi.vercelAiChannelIntegration, | ||
| hapiIntegration: hapi.hapiChannelIntegration | ||
| }; | ||
| exports.anthropicChannelIntegration = anthropic.anthropicChannelIntegration; | ||
| exports.hapiChannelIntegration = hapi.hapiChannelIntegration; | ||
| exports.ioredisChannelIntegration = ioredis.ioredisChannelIntegration; | ||
| exports.lruMemoizerChannelIntegration = lruMemoizer.lruMemoizerChannelIntegration; | ||
| exports.mysqlChannelIntegration = mysql.mysqlChannelIntegration; | ||
| exports.openaiChannelIntegration = openai.openaiChannelIntegration; | ||
| exports.postgresChannelIntegration = postgres.postgresChannelIntegration; | ||
| exports.vercelAiChannelIntegration = vercelAi.vercelAiChannelIntegration; | ||
| exports.detectOrchestrionSetup = detect.detectOrchestrionSetup; | ||
| exports.mysqlChannelIntegration = mysql.mysqlChannelIntegration; | ||
| exports.lruMemoizerChannelIntegration = lruMemoizer.lruMemoizerChannelIntegration; | ||
| exports.isOrchestrionInjected = detect.isOrchestrionInjected; | ||
| exports.channelIntegrations = channelIntegrations; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"} | ||
| {"version":3,"file":"index.js","sources":["../../../src/orchestrion/index.ts"],"sourcesContent":["import { anthropicChannelIntegration } from '../integrations/tracing-channel/anthropic';\nimport { hapiChannelIntegration } from '../integrations/tracing-channel/hapi';\nimport { ioredisChannelIntegration } from '../integrations/tracing-channel/ioredis';\nimport { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer';\nimport { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql';\nimport { openaiChannelIntegration } from '../integrations/tracing-channel/openai';\nimport { postgresChannelIntegration } from '../integrations/tracing-channel/postgres';\nimport { vercelAiChannelIntegration } from '../integrations/tracing-channel/vercel-ai';\n\nexport { detectOrchestrionSetup, isOrchestrionInjected } from './detect';\nexport {\n anthropicChannelIntegration,\n hapiChannelIntegration,\n ioredisChannelIntegration,\n lruMemoizerChannelIntegration,\n mysqlChannelIntegration,\n openaiChannelIntegration,\n postgresChannelIntegration,\n vercelAiChannelIntegration,\n};\nexport type { IORedisChannelIntegrationOptions, IORedisResponseHook } from '../integrations/tracing-channel/ioredis';\n\n/**\n * The canonical set of orchestrion diagnostics-channel integrations, keyed by their public\n * (OTel-parity) factory name.\n *\n * Single source of truth: add a new channel integration here and every consumer — the `@sentry/node`\n * opt-in helper (`experimentalUseDiagnosticsChannelInjection`) and its public\n * `diagnosticsChannelInjectionIntegrations()` map — picks it up automatically, so there's no separate\n * list to keep in sync.\n *\n * NOTE: `ioredisChannelIntegration` is intentionally NOT here. It only partially replaces the\n * composite OTel `Redis` integration and needs the node SDK's redis cache `responseHook` (which\n * can't live in `server-utils`), so `@sentry/node` wires it up separately.\n */\nexport const channelIntegrations = {\n postgresIntegration: postgresChannelIntegration,\n mysqlIntegration: mysqlChannelIntegration,\n lruMemoizerIntegration: lruMemoizerChannelIntegration,\n openaiIntegration: openaiChannelIntegration,\n anthropicIntegration: anthropicChannelIntegration,\n vercelAiIntegration: vercelAiChannelIntegration,\n hapiIntegration: hapiChannelIntegration,\n} as const;\n"],"names":["postgresChannelIntegration","mysqlChannelIntegration","lruMemoizerChannelIntegration","openaiChannelIntegration","anthropicChannelIntegration","vercelAiChannelIntegration","hapiChannelIntegration"],"mappings":";;;;;;;;;;;;AAmCO,MAAM,mBAAA,GAAsB;AAAA,EACjC,mBAAA,EAAqBA,mCAAA;AAAA,EACrB,gBAAA,EAAkBC,6BAAA;AAAA,EAClB,sBAAA,EAAwBC,yCAAA;AAAA,EACxB,iBAAA,EAAmBC,+BAAA;AAAA,EACnB,oBAAA,EAAsBC,qCAAA;AAAA,EACtB,mBAAA,EAAqBC,mCAAA;AAAA,EACrB,eAAA,EAAiBC;AACnB;;;;;;;;;;;;;;"} |
@@ -7,5 +7,4 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const debugBuild = require('../../debug-build.js'); | ||
| const config = require('../config.js'); | ||
| const index = require('../config/index.js'); | ||
| var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null; | ||
| function registerDiagnosticsChannelInjection() { | ||
@@ -21,3 +20,4 @@ const g = globalThis.__SENTRY_ORCHESTRION__ ?? (globalThis.__SENTRY_ORCHESTRION__ = {}); | ||
| const stableSyncHooks = (nodeVersion[0] ?? 0) > 25 || nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1 || nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13 || (denoVersion[0] ?? 0) > 2 || denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8; | ||
| const nodeRequire = typeof require === "function" ? require : Module.createRequire((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('orchestrion/runtime/register.js', document.baseURI).href))); | ||
| let nodeRequire; | ||
| nodeRequire = require; | ||
| const mod = Module; | ||
@@ -27,11 +27,14 @@ try { | ||
| const { initialize, resolve, load } = nodeRequire("@apm-js-collab/tracing-hooks/hook-sync.mjs"); | ||
| initialize({ instrumentations: config.SENTRY_INSTRUMENTATIONS }); | ||
| initialize({ instrumentations: index.SENTRY_INSTRUMENTATIONS }); | ||
| mod.registerHooks({ resolve, load }); | ||
| debugBuild.DEBUG_BUILD && core.debug.log("[orchestrion] registered diagnostics-channel injection via Module.registerHooks()"); | ||
| } else if (typeof mod.register === "function" && !globalAny.Bun && !globalAny.Deno) { | ||
| mod.register(node_url.pathToFileURL(nodeRequire.resolve("@apm-js-collab/tracing-hooks/hook.mjs")).href, { | ||
| data: { instrumentations: config.SENTRY_INSTRUMENTATIONS } | ||
| let parentURL; | ||
| parentURL = node_url.pathToFileURL(__filename).href; | ||
| mod.register("@apm-js-collab/tracing-hooks/hook.mjs", { | ||
| parentURL, | ||
| data: { instrumentations: index.SENTRY_INSTRUMENTATIONS } | ||
| }); | ||
| const ModulePatch = nodeRequire("@apm-js-collab/tracing-hooks"); | ||
| new ModulePatch({ instrumentations: config.SENTRY_INSTRUMENTATIONS }).patch(); | ||
| new ModulePatch({ instrumentations: index.SENTRY_INSTRUMENTATIONS }).patch(); | ||
| debugBuild.DEBUG_BUILD && core.debug.log("[orchestrion] registered diagnostics-channel injection via Module.register()"); | ||
@@ -38,0 +41,0 @@ } else { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"register.js","sources":["../../../../src/orchestrion/runtime/register.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { createRequire } from 'node:module';\nimport * as Module from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { SENTRY_INSTRUMENTATIONS } from '../config';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Synchronously register the diagnostics-channel injection module hooks.\n *\n * This is the single source of truth for the registration logic. It is used by:\n * - `Sentry.init()` (the Node SDK calls it directly — that's why this module\n * must be CJS-compatible / dual-built, so it can be `require()`d synchronously\n * before the app's `import`s resolve), and\n * - `import-hook.mjs`, the side-effecting `--import` entry, which just calls it.\n *\n * Libraries imported *after* this call publish the `tracingChannel` events that\n * the channel-based integrations subscribe to.\n *\n * Idempotent via `globalThis.__SENTRY_ORCHESTRION__` — a no-op if the runtime\n * `--import` hook or a bundler plugin already injected the channels.\n */\nexport function registerDiagnosticsChannelInjection(): void {\n const g = (globalThis.__SENTRY_ORCHESTRION__ ??= {});\n\n // Already injected (runtime --import hook or bundler plugin) — nothing to do.\n if (g.runtime || g.bundler) {\n return;\n }\n\n const globalAny = globalThis as { Bun?: unknown; Deno?: { version?: { deno?: string } } };\n const parseVersion = (v: string): number[] => v.split('.').map(n => parseInt(n, 10));\n const nodeVersion = parseVersion(process.versions.node ?? '0.0.0');\n const denoVersion = parseVersion(globalAny.Deno?.version?.deno ?? '0.0.0');\n // `Module.registerHooks` only became stable in Node 24.13 / 25.1 and Deno 2.8.\n const stableSyncHooks =\n (nodeVersion[0] ?? 0) > 25 ||\n (nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1) ||\n (nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13) ||\n (denoVersion[0] ?? 0) > 2 ||\n (denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8);\n\n // Prefer the builtin `require` if possible. This is present in CommonJS,\n // including a bundler's CJS output, so no need to ever have to evaluate\n // `import.meta.url` there.\n //\n // esbuild and friends rewrite `import.meta.url` to `{}` for CJS output,\n // which would make `createRequire(undefined)` throw.\n // Only use `import.meta.url` in true ESM, where there's no `require`\n const nodeRequire = typeof require === 'function' ? require : createRequire(import.meta.url);\n\n // `Module.registerHooks` / `Module.register` are newer than the @types/node\n // we build against, hence the cast.\n const mod = Module as unknown as {\n registerHooks?: (hooks: unknown) => void;\n register?: (specifier: string, options: unknown) => void;\n };\n\n // runs both at `--import` time and (synchronously) inside `Sentry.init()`,\n // so an unguarded throw would either abort startup or make `init()` throw.\n // On any failure (e.g. dep resolution, `require(esm)` / Node-compat\n // incompatibility) we warn (DEBUG only) and continue without channel\n // injection\n try {\n if (typeof mod.registerHooks === 'function' && stableSyncHooks) {\n // Sync hooks cover CJS and ESM, no separate `_compile` patch needed.\n // We require() the module here so that we can synchronously load it,\n // including from a CommonJS Sentry build, without bundlers pulling in.\n // All versions in stableSyncHooks support this.\n const { initialize, resolve, load } = nodeRequire('@apm-js-collab/tracing-hooks/hook-sync.mjs') as {\n initialize: (opts: { instrumentations: unknown }) => void;\n resolve: unknown;\n load: unknown;\n };\n initialize({ instrumentations: SENTRY_INSTRUMENTATIONS });\n mod.registerHooks({ resolve, load });\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.registerHooks()');\n } else if (typeof mod.register === 'function' && !globalAny.Bun && !globalAny.Deno) {\n // `Module.register` + the `_compile` patch is Node 18.19–24.12 / 25.0\n // path. Bun/Deno are excluded: they don't support this combination and\n // must use the stable `registerHooks` path above (or none at all).\n // Resolve the hook to an absolute file URL ourselves so\n // `Module.register` needs no `parentURL`, so no need for\n // `import.meta.url` polyfilling\n mod.register(pathToFileURL(nodeRequire.resolve('@apm-js-collab/tracing-hooks/hook.mjs')).href, {\n data: { instrumentations: SENTRY_INSTRUMENTATIONS },\n });\n\n // ALSO patch `Module.prototype._compile` for the CJS side: when an ESM\n // file `import`s a CJS package, the package's internal `require()` calls\n // are resolved through the CJS machinery and never reach the ESM\n // register hook, so without this patch the file we want to instrument\n // loads untransformed.\n const ModulePatch = nodeRequire('@apm-js-collab/tracing-hooks') as new (opts: { instrumentations: unknown }) => {\n patch: () => void;\n };\n new ModulePatch({ instrumentations: SENTRY_INSTRUMENTATIONS }).patch();\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.register()');\n } else {\n DEBUG_BUILD &&\n debug.warn('[Sentry] No available Node API to register diagnostics-channel injection hooks; skipping.');\n return;\n }\n } catch (error) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] Failed to register diagnostics-channel injection hooks; channel-based integrations ' +\n 'will not record spans.',\n error,\n );\n return;\n }\n\n g.runtime = true;\n}\n"],"names":["createRequire","SENTRY_INSTRUMENTATIONS","DEBUG_BUILD","debug","pathToFileURL"],"mappings":";;;;;;;;;AA2BO,SAAS,mCAAA,GAA4C;AAC1D,EAAA,MAAM,CAAA,GAAK,UAAA,CAAW,sBAAA,KAAX,UAAA,CAAW,yBAA2B,EAAC,CAAA;AAGlD,EAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,EAAS;AAC1B,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAwB,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AACnF,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,QAAQ,OAAO,CAAA;AACjE,EAAA,MAAM,cAAc,YAAA,CAAa,SAAA,CAAU,IAAA,EAAM,OAAA,EAAS,QAAQ,OAAO,CAAA;AAEzE,EAAA,MAAM,mBACH,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,MACvB,WAAA,CAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,YAAY,CAAC,CAAA,IAAK,CAAA,KAAM,CAAA,IAClD,YAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,KAAM,EAAA,IAAA,CAClD,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,IACvB,WAAA,CAAY,CAAC,CAAA,KAAM,CAAA,IAAA,CAAM,WAAA,CAAY,CAAC,KAAK,CAAA,KAAM,CAAA;AASpD,EAAA,MAAM,cAAc,OAAO,OAAA,KAAY,aAAa,OAAA,GAAUA,oBAAA,CAAc,iRAAe,CAAA;AAI3F,EAAA,MAAM,GAAA,GAAM,MAAA;AAUZ,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,GAAA,CAAI,aAAA,KAAkB,UAAA,IAAc,eAAA,EAAiB;AAK9D,MAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,IAAA,EAAK,GAAI,YAAY,4CAA4C,CAAA;AAK9F,MAAA,UAAA,CAAW,EAAE,gBAAA,EAAkBC,8BAAA,EAAyB,CAAA;AACxD,MAAA,GAAA,CAAI,aAAA,CAAc,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AACnC,MAAAC,sBAAA,IAAeC,UAAA,CAAM,IAAI,mFAAmF,CAAA;AAAA,IAC9G,CAAA,MAAA,IAAW,OAAO,GAAA,CAAI,QAAA,KAAa,UAAA,IAAc,CAAC,SAAA,CAAU,GAAA,IAAO,CAAC,SAAA,CAAU,IAAA,EAAM;AAOlF,MAAA,GAAA,CAAI,SAASC,sBAAA,CAAc,WAAA,CAAY,QAAQ,uCAAuC,CAAC,EAAE,IAAA,EAAM;AAAA,QAC7F,IAAA,EAAM,EAAE,gBAAA,EAAkBH,8BAAA;AAAwB,OACnD,CAAA;AAOD,MAAA,MAAM,WAAA,GAAc,YAAY,8BAA8B,CAAA;AAG9D,MAAA,IAAI,YAAY,EAAE,gBAAA,EAAkBA,8BAAA,EAAyB,EAAE,KAAA,EAAM;AACrE,MAAAC,sBAAA,IAAeC,UAAA,CAAM,IAAI,8EAA8E,CAAA;AAAA,IACzG,CAAA,MAAO;AACL,MAAAD,sBAAA,IACEC,UAAA,CAAM,KAAK,2FAA2F,CAAA;AACxG,MAAA;AAAA,IACF;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAAD,sBAAA,IACEC,UAAA,CAAM,IAAA;AAAA,MACJ,oHAAA;AAAA,MAEA;AAAA,KACF;AACF,IAAA;AAAA,EACF;AAEA,EAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACd;;;;"} | ||
| {"version":3,"file":"register.js","sources":["../../../../src/orchestrion/runtime/register.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { createRequire } from 'node:module';\nimport * as Module from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { SENTRY_INSTRUMENTATIONS } from '../config';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Synchronously register the diagnostics-channel injection module hooks.\n *\n * This is the single source of truth for the registration logic. It is used by:\n * - `Sentry.init()` (the Node SDK calls it directly — that's why this module\n * must be CJS-compatible / dual-built, so it can be `require()`d synchronously\n * before the app's `import`s resolve), and\n * - `import-hook.mjs`, the side-effecting `--import` entry, which just calls it.\n *\n * Libraries imported *after* this call publish the `tracingChannel` events that\n * the channel-based integrations subscribe to.\n *\n * Idempotent via `globalThis.__SENTRY_ORCHESTRION__` — a no-op if the runtime\n * `--import` hook or a bundler plugin already injected the channels.\n */\nexport function registerDiagnosticsChannelInjection(): void {\n const g = (globalThis.__SENTRY_ORCHESTRION__ ??= {});\n\n // Already injected (runtime --import hook or bundler plugin) — nothing to do.\n if (g.runtime || g.bundler) {\n return;\n }\n\n const globalAny = globalThis as { Bun?: unknown; Deno?: { version?: { deno?: string } } };\n const parseVersion = (v: string): number[] => v.split('.').map(n => parseInt(n, 10));\n const nodeVersion = parseVersion(process.versions.node ?? '0.0.0');\n const denoVersion = parseVersion(globalAny.Deno?.version?.deno ?? '0.0.0');\n // `Module.registerHooks` only became stable in Node 24.13 / 25.1 and Deno 2.8.\n const stableSyncHooks =\n (nodeVersion[0] ?? 0) > 25 ||\n (nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1) ||\n (nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13) ||\n (denoVersion[0] ?? 0) > 2 ||\n (denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8);\n\n let nodeRequire: (specifier: string) => unknown;\n /*! rollup-include-cjs-only */\n nodeRequire = require;\n /*! rollup-include-cjs-only-end */\n /*! rollup-include-esm-only */\n nodeRequire = createRequire(import.meta.url);\n /*! rollup-include-esm-only-end */\n\n // `Module.registerHooks` / `Module.register` are newer than the @types/node\n // we build against, hence the cast.\n const mod = Module as unknown as {\n registerHooks?: (hooks: unknown) => void;\n register?: (specifier: string, options: unknown) => void;\n };\n\n // runs both at `--import` time and (synchronously) inside `Sentry.init()`,\n // so an unguarded throw would either abort startup or make `init()` throw.\n // On any failure (e.g. dep resolution, `require(esm)` / Node-compat\n // incompatibility) we warn (DEBUG only) and continue without channel\n // injection\n try {\n if (typeof mod.registerHooks === 'function' && stableSyncHooks) {\n // Sync hooks cover CJS and ESM, no separate `_compile` patch needed.\n // We require() the module here so that we can synchronously load it,\n // including from a CommonJS Sentry build, without bundlers pulling in.\n // All versions in stableSyncHooks support this.\n const { initialize, resolve, load } = nodeRequire('@apm-js-collab/tracing-hooks/hook-sync.mjs') as {\n initialize: (opts: { instrumentations: unknown }) => void;\n resolve: unknown;\n load: unknown;\n };\n initialize({ instrumentations: SENTRY_INSTRUMENTATIONS });\n mod.registerHooks({ resolve, load });\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.registerHooks()');\n } else if (typeof mod.register === 'function' && !globalAny.Bun && !globalAny.Deno) {\n // `Module.register` + the `_compile` patch is Node 18.19–24.12 / 25.0\n // path. Bun/Deno are excluded: they don't support this combination and\n // must use the stable `registerHooks` path above (or none at all).\n let parentURL: string;\n /*! rollup-include-cjs-only */\n parentURL = pathToFileURL(__filename).href;\n /*! rollup-include-cjs-only-end */\n /*! rollup-include-esm-only */\n parentURL = import.meta.url;\n /*! rollup-include-esm-only-end */\n\n mod.register('@apm-js-collab/tracing-hooks/hook.mjs', {\n parentURL,\n data: { instrumentations: SENTRY_INSTRUMENTATIONS },\n });\n\n // ALSO patch `Module.prototype._compile` for the CJS side: when an ESM\n // file `import`s a CJS package, the package's internal `require()` calls\n // are resolved through the CJS machinery and never reach the ESM\n // register hook, so without this patch the file we want to instrument\n // loads untransformed.\n const ModulePatch = nodeRequire('@apm-js-collab/tracing-hooks') as new (opts: { instrumentations: unknown }) => {\n patch: () => void;\n };\n new ModulePatch({ instrumentations: SENTRY_INSTRUMENTATIONS }).patch();\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.register()');\n } else {\n DEBUG_BUILD &&\n debug.warn('[Sentry] No available Node API to register diagnostics-channel injection hooks; skipping.');\n return;\n }\n } catch (error) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] Failed to register diagnostics-channel injection hooks; channel-based integrations ' +\n 'will not record spans.',\n error,\n );\n return;\n }\n\n g.runtime = true;\n}\n"],"names":["SENTRY_INSTRUMENTATIONS","DEBUG_BUILD","debug","pathToFileURL"],"mappings":";;;;;;;;AA2BO,SAAS,mCAAA,GAA4C;AAC1D,EAAA,MAAM,CAAA,GAAK,UAAA,CAAW,sBAAA,KAAX,UAAA,CAAW,yBAA2B,EAAC,CAAA;AAGlD,EAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,EAAS;AAC1B,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAwB,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AACnF,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,QAAQ,OAAO,CAAA;AACjE,EAAA,MAAM,cAAc,YAAA,CAAa,SAAA,CAAU,IAAA,EAAM,OAAA,EAAS,QAAQ,OAAO,CAAA;AAEzE,EAAA,MAAM,mBACH,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,MACvB,WAAA,CAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,YAAY,CAAC,CAAA,IAAK,CAAA,KAAM,CAAA,IAClD,YAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,KAAM,EAAA,IAAA,CAClD,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,IACvB,WAAA,CAAY,CAAC,CAAA,KAAM,CAAA,IAAA,CAAM,WAAA,CAAY,CAAC,KAAK,CAAA,KAAM,CAAA;AAEpD,EAAA,IAAI,WAAA;AAAA,EACJ,WAAA,GAAA,OAAA;AACA,EAAA,MAAA,GAAA,GAAA,MAAc;AAAA,EACd,IAAA;AAAA,IACA,IAAA,OAAA,GAAA,CAAA,aAAA,KAAA,UAAA,IAAA,eAAA,EAAA;AACA,MAAA,MAAA,EAAA,UAAc,EAAA,kBAA0B,WAAG,CAAA,4CAAA,CAAA;AAAA,MAC3C,UAAA,CAAA,EAAA,gBAAA,EAAAA,6BAAA,EAAA,CAAA;AAIA,MAAA,GAAM,CAAA,aAAM,CAAA,EAAA,OAAA,EAAA,IAAA,EAAA,CAAA;AAUZ,MAAIC,sBAAA,IAAAC,UAAA,CAAA,GAAA,CAAA,mFAAA,CAAA;AACF,IAAA,CAAA,MAAI,IAAO,OAAI,GAAA,CAAA,QAAA,KAAkB,UAAA,IAAc,CAAA,SAAA,CAAA,GAAA,IAAiB,CAAA,SAAA,CAAA,IAAA,EAAA;AAK9D,MAAA,IAAA,SAAQ;AAKR,MAAA,SAAA,GAAWC,sBAAE,CAAA,UAAkB,CAAA,CAAA,IAAA;AAC/B,MAAA,GAAA,CAAI,QAAA,CAAA,uCAA+B,EAAA;AACnC,QAAA,SAAA;AAA4G,QAC9G,IAAA,EAAA,EAAW,gBAAW,EAAAH,6BAA4B;AAIhD,OAAA,CAAA;AAAI,MACJ,MAAA,WAAA,GAAA,WAAA,CAAA,8BAAA,CAAA;AACA,MAAA,IAAA,WAAY,CAAA,EAAA,kBAAwBA,6BAAE,EAAA,CAAA,CAAA,KAAA,EAAA;AAAA,MACtCC,sBAAA,IAAAC,UAAA,CAAA,GAAA,CAAA,8EAAA,CAAA;AAAA,IAAA,CAAA,MACA;AACA,MAAAD,sBAAA,IAAYC,UAAA,CAAA,IAAY,CAAA,2FAAA,CAAA;AAAA,MACxB;AAEA,IAAA;AAAsD,EAAA,CAAA,CAAA,OACpD,KAAA,EAAA;AAAA,IAAAD,sBACM,IAAEC,UAAA,CAAA,IAAA;AAA0C,MACpD,oHAAC;AAOD,MAAA;AAGA,KAAA;AACA,IAAA;AAAuG,EAAA;AAEvG,EAAA,CAAA,CAAA,OAAA,GAAA,IAAA;AAEA;;;;"} |
@@ -122,3 +122,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const raw = isObject ? "message" in error ? error.message : void 0 : error; | ||
| const message = raw ? String(raw) : "unknown_error"; | ||
| const message = raw ? String(raw) : void 0; | ||
| const type = isObject && "name" in error ? String(error.name) : "unknown"; | ||
@@ -125,0 +125,0 @@ return { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"tracing-channel.js","sources":["../../src/tracing-channel.ts"],"sourcesContent":["import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\nimport type { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core';\nimport { debug, captureException, SPAN_STATUS_ERROR, getAsyncContextStrategy, getMainCarrier } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n /**\n * The current active span for the traced call.\n */\n _sentrySpan?: Span;\n\n /**\n * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing.\n */\n _sentryCallerStore?: unknown;\n};\n\n/*\n * A type patch so that we don't have to handle all subscription types.\n */\nexport interface SentryTracingChannel<TData extends object = object> extends Omit<\n TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>,\n 'subscribe' | 'unsubscribe'\n> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n}\n\nexport interface TracingChannelLifeCycleOptions<TData extends object = object> {\n /**\n * Invoked with the span and the channel context object once the traced operation completes\n * Use it to enrich the span from the result/error (branch on `'error' in data` / `'result' in data`) or to run cleanup.\n */\n beforeSpanEnd?: (span: Span, data: TracingChannelPayloadWithSpan<TData>) => void;\n\n /**\n * Whether a thrown error is captured as a Sentry event. The span is always marked with error status regardless. Defaults to `false`.\n * You can alternatively pass a function that sets the ExclusiveEventHintOrCaptureContext on the captured error.\n * Set `true` for instrumentations that own the error boundary, (e.g: route handlers)\n * For database drivers, it is not recommended to set this at all.\n */\n captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext);\n\n /**\n * Take ownership of *when* the span ends: return `true` and the helper won't end it on\n * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that\n * completes via its own `'end'`/`'error'` events.\n *\n * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span\n * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false`\n * lets the helper end the span as usual.\n */\n deferSpanEnd?: (args: {\n span: Span;\n data: TracingChannelPayloadWithSpan<TData>;\n /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */\n end: (error?: unknown) => void;\n }) => boolean;\n}\n\n/** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */\nexport interface TracingChannelBindingHandle<TData extends object = object> {\n /**\n * The tracing channel with the span bound into async context.\n */\n channel: SentryTracingChannel<TData>;\n\n /**\n * Tears down the binding: unsubscribes lifecycle handlers, when present, and unbinds the start store.\n * Idempotent, and a no-op when no async context binding was available.\n */\n unbind: () => void;\n}\n\nconst NOOP = (): void => {};\n\n/**\n * Bind a span and its lifecycle to a tracing channel so the span becomes the active async context\n * for the traced operation and is ended when the operation completes.\n *\n * `getSpan` may return `undefined` to opt a payload out entirely: nothing is bound, no span is\n * tracked, and the active context is left untouched. Use it for events that ride the same channel\n * but should reuse the enclosing span instead of opening (and ending) their own — e.g. an agent\n * loop's per-step events, where ending a freshly opened span would close the parent prematurely.\n */\nexport function bindTracingChannelToSpan<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n opts?: TracingChannelLifeCycleOptions<TData>,\n): TracingChannelBindingHandle<TData> {\n const handle = bindSpanToChannelStore(channel, getSpan);\n\n const beforeSpanEnd = opts?.beforeSpanEnd;\n const deferSpanEnd = opts?.deferSpanEnd;\n const getErrorHint = (e: unknown): ExclusiveEventHintOrCaptureContext => {\n if (typeof opts?.captureError === 'function') {\n return opts.captureError(e);\n }\n\n return {\n mechanism: {\n type: 'auto.diagnostic_channels.bind_span',\n handled: false,\n },\n };\n };\n\n // Apply Sentry error status + attributes (and capture, if configured) to a span. Shared by the\n // channel `error` lifecycle and the deferred `end` util so the two can't drift.\n const annotateSpanError = (span: Span, error: unknown): void => {\n if (opts?.captureError) {\n captureException(error, getErrorHint(error));\n }\n\n const { message, attributes } = getErrorInfo(error);\n span.setStatus({ code: SPAN_STATUS_ERROR, message });\n span.setAttributes(attributes);\n };\n\n // Creates an end fn for deferred handlers to use, ensures consistent span end behavior\n const makeDeferredEnd = (span: Span, data: TracingChannelPayloadWithSpan<TData>) => {\n let ended = false;\n\n return (error?: unknown): void => {\n if (ended) {\n return;\n }\n\n ended = true;\n if (error !== undefined) {\n annotateSpanError(span, error);\n }\n\n endBoundSpan(data, beforeSpanEnd);\n };\n };\n\n const subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>> = {\n start: NOOP,\n asyncStart: NOOP,\n end(data) {\n // The operation settled synchronously (returned or threw)\n // Presence checks because caller can return `undefined` result or throw a falsy value.\n if ('error' in data || 'result' in data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n }\n },\n error(data) {\n // No span was bound for this payload (`getSpan` returned undefined), so there is nothing to\n // annotate and no instrumentation that owns capturing this error.\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n\n annotateSpanError(span, data.error);\n },\n asyncEnd(data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n },\n };\n\n handle.channel.subscribe(subscribers);\n\n return {\n channel: handle.channel,\n unbind: () => {\n handle.channel.unsubscribe(subscribers);\n handle.unbind();\n },\n };\n}\n\n/**\n * Bind a span into the channel's async context so it becomes active for the traced operation,\n * without managing its lifecycle. The primitive behind {@link bindTracingChannelToSpan}, which\n * layers span-ending and error handling on top.\n *\n * `getSpan` may return `undefined` to leave the active context untouched for that payload.\n */\nfunction bindSpanToChannelStore<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n): TracingChannelBindingHandle<TData> {\n // Grabs the tracing channel binding defined by the AsyncContext strategy implementation\n const binding = getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.();\n\n // If no binding, then either the implementer doesn't support tracing channels or there is no active strategy\n // Failure mode here means we would still access the channel and potentially subscribe to it, but parenting will be off.\n if (!binding) {\n DEBUG_BUILD && debug.log('[TracingChannel] Could not access async context binding.');\n\n return {\n channel,\n unbind: NOOP,\n };\n }\n\n // Grab the ALS instance, we don't really care what is in it as long as the AsyncContext strategy can use its value to figure out parenting.\n const asyncLocalStorage = binding.asyncLocalStorage as AsyncLocalStorage<TData>;\n\n // bindStore activates the ALS for the traced call; any getStore() inside it returns the value bound for that context.\n // 1. Produce: getStoreWithActiveSpan(span) clones the current scope, plants the span via _INTERNAL_setSpanForScope, and returns { scope, isolationScope }, the active context carrying our span.\n // 2. Bind: the courier hands that opaque value to channel.start.bindStore(asyncLocalStorage, producer), which runs the traced op inside asyncLocalStorage.run(value, …); it never inspects the value.\n // 3. Read: inside the op, Sentry's scope machinery calls getScopes() → asyncStorage.getStore() on that same ALS, so getCurrentScope/getIsolationScope/getActiveSpan resolve to the scope carrying our span.\n // 4. Nest: any child span started in the traced op parents to that active span.\n channel.start.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n // Stash the caller's store before we swap in the span store, so `asyncStart` can restore it for\n // callback-style channels (see `_sentryCallerStore`).\n data._sentryCallerStore = asyncLocalStorage.getStore();\n\n const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return data._sentryCallerStore as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n // Restore the caller's context for the async continuation. Only callback-style channels `runStores`\n // `asyncStart` (so the callback runs inside this store). promise channels `publish` it, leaving this\n // inert, their continuation already inherits the caller's context natively.\n channel.asyncStart.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n return data._sentryCallerStore as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the stores\n channel.start.unbindStore(asyncLocalStorage);\n channel.asyncStart.unbindStore(asyncLocalStorage);\n },\n };\n}\n\nfunction endBoundSpan<TData extends object>(\n data: TracingChannelPayloadWithSpan<TData>,\n beforeSpanEnd: TracingChannelLifeCycleOptions<TData>['beforeSpanEnd'],\n): void {\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n beforeSpanEnd?.(span, data);\n span.end();\n}\n\ntype ErrorInfo = {\n message: string;\n attributes: Record<string, string>;\n};\n\n/**\n * Best-effort message and attribute extraction for thrown/rejected values.\n */\nfunction getErrorInfo(error: unknown): ErrorInfo {\n const isObject = !!error && typeof error === 'object';\n const raw = isObject ? ('message' in error ? error.message : undefined) : error;\n\n const message = raw ? String(raw) : 'unknown_error';\n const type = isObject && 'name' in error ? String(error.name) : 'unknown';\n\n return {\n message,\n attributes: {\n [ERROR_TYPE]: type,\n },\n };\n}\n"],"names":["captureException","SPAN_STATUS_ERROR","getAsyncContextStrategy","getMainCarrier","DEBUG_BUILD","debug","ERROR_TYPE"],"mappings":"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"} | ||
| {"version":3,"file":"tracing-channel.js","sources":["../../src/tracing-channel.ts"],"sourcesContent":["import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\nimport type { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core';\nimport { debug, captureException, SPAN_STATUS_ERROR, getAsyncContextStrategy, getMainCarrier } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n /**\n * The current active span for the traced call.\n */\n _sentrySpan?: Span;\n\n /**\n * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing.\n */\n _sentryCallerStore?: unknown;\n};\n\n/*\n * A type patch so that we don't have to handle all subscription types.\n */\nexport interface SentryTracingChannel<TData extends object = object> extends Omit<\n TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>,\n 'subscribe' | 'unsubscribe'\n> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n}\n\nexport interface TracingChannelLifeCycleOptions<TData extends object = object> {\n /**\n * Invoked with the span and the channel context object once the traced operation completes\n * Use it to enrich the span from the result/error (branch on `'error' in data` / `'result' in data`) or to run cleanup.\n */\n beforeSpanEnd?: (span: Span, data: TracingChannelPayloadWithSpan<TData>) => void;\n\n /**\n * Whether a thrown error is captured as a Sentry event. The span is always marked with error status regardless. Defaults to `false`.\n * You can alternatively pass a function that sets the ExclusiveEventHintOrCaptureContext on the captured error.\n * Set `true` for instrumentations that own the error boundary, (e.g: route handlers)\n * For database drivers, it is not recommended to set this at all.\n */\n captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext);\n\n /**\n * Take ownership of *when* the span ends: return `true` and the helper won't end it on\n * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that\n * completes via its own `'end'`/`'error'` events.\n *\n * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span\n * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false`\n * lets the helper end the span as usual.\n */\n deferSpanEnd?: (args: {\n span: Span;\n data: TracingChannelPayloadWithSpan<TData>;\n /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */\n end: (error?: unknown) => void;\n }) => boolean;\n}\n\n/** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */\nexport interface TracingChannelBindingHandle<TData extends object = object> {\n /**\n * The tracing channel with the span bound into async context.\n */\n channel: SentryTracingChannel<TData>;\n\n /**\n * Tears down the binding: unsubscribes lifecycle handlers, when present, and unbinds the start store.\n * Idempotent, and a no-op when no async context binding was available.\n */\n unbind: () => void;\n}\n\nconst NOOP = (): void => {};\n\n/**\n * Bind a span and its lifecycle to a tracing channel so the span becomes the active async context\n * for the traced operation and is ended when the operation completes.\n *\n * `getSpan` may return `undefined` to opt a payload out entirely: nothing is bound, no span is\n * tracked, and the active context is left untouched. Use it for events that ride the same channel\n * but should reuse the enclosing span instead of opening (and ending) their own — e.g. an agent\n * loop's per-step events, where ending a freshly opened span would close the parent prematurely.\n */\nexport function bindTracingChannelToSpan<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n opts?: TracingChannelLifeCycleOptions<TData>,\n): TracingChannelBindingHandle<TData> {\n const handle = bindSpanToChannelStore(channel, getSpan);\n\n const beforeSpanEnd = opts?.beforeSpanEnd;\n const deferSpanEnd = opts?.deferSpanEnd;\n const getErrorHint = (e: unknown): ExclusiveEventHintOrCaptureContext => {\n if (typeof opts?.captureError === 'function') {\n return opts.captureError(e);\n }\n\n return {\n mechanism: {\n type: 'auto.diagnostic_channels.bind_span',\n handled: false,\n },\n };\n };\n\n // Apply Sentry error status + attributes (and capture, if configured) to a span. Shared by the\n // channel `error` lifecycle and the deferred `end` util so the two can't drift.\n const annotateSpanError = (span: Span, error: unknown): void => {\n if (opts?.captureError) {\n captureException(error, getErrorHint(error));\n }\n\n const { message, attributes } = getErrorInfo(error);\n span.setStatus({ code: SPAN_STATUS_ERROR, message });\n span.setAttributes(attributes);\n };\n\n // Creates an end fn for deferred handlers to use, ensures consistent span end behavior\n const makeDeferredEnd = (span: Span, data: TracingChannelPayloadWithSpan<TData>) => {\n let ended = false;\n\n return (error?: unknown): void => {\n if (ended) {\n return;\n }\n\n ended = true;\n if (error !== undefined) {\n annotateSpanError(span, error);\n }\n\n endBoundSpan(data, beforeSpanEnd);\n };\n };\n\n const subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>> = {\n start: NOOP,\n asyncStart: NOOP,\n end(data) {\n // The operation settled synchronously (returned or threw)\n // Presence checks because caller can return `undefined` result or throw a falsy value.\n if ('error' in data || 'result' in data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n }\n },\n error(data) {\n // No span was bound for this payload (`getSpan` returned undefined), so there is nothing to\n // annotate and no instrumentation that owns capturing this error.\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n\n annotateSpanError(span, data.error);\n },\n asyncEnd(data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n },\n };\n\n handle.channel.subscribe(subscribers);\n\n return {\n channel: handle.channel,\n unbind: () => {\n handle.channel.unsubscribe(subscribers);\n handle.unbind();\n },\n };\n}\n\n/**\n * Bind a span into the channel's async context so it becomes active for the traced operation,\n * without managing its lifecycle. The primitive behind {@link bindTracingChannelToSpan}, which\n * layers span-ending and error handling on top.\n *\n * `getSpan` may return `undefined` to leave the active context untouched for that payload.\n */\nfunction bindSpanToChannelStore<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n): TracingChannelBindingHandle<TData> {\n // Grabs the tracing channel binding defined by the AsyncContext strategy implementation\n const binding = getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.();\n\n // If no binding, then either the implementer doesn't support tracing channels or there is no active strategy\n // Failure mode here means we would still access the channel and potentially subscribe to it, but parenting will be off.\n if (!binding) {\n DEBUG_BUILD && debug.log('[TracingChannel] Could not access async context binding.');\n\n return {\n channel,\n unbind: NOOP,\n };\n }\n\n // Grab the ALS instance, we don't really care what is in it as long as the AsyncContext strategy can use its value to figure out parenting.\n const asyncLocalStorage = binding.asyncLocalStorage as AsyncLocalStorage<TData>;\n\n // bindStore activates the ALS for the traced call; any getStore() inside it returns the value bound for that context.\n // 1. Produce: getStoreWithActiveSpan(span) clones the current scope, plants the span via _INTERNAL_setSpanForScope, and returns { scope, isolationScope }, the active context carrying our span.\n // 2. Bind: the courier hands that opaque value to channel.start.bindStore(asyncLocalStorage, producer), which runs the traced op inside asyncLocalStorage.run(value, …); it never inspects the value.\n // 3. Read: inside the op, Sentry's scope machinery calls getScopes() → asyncStorage.getStore() on that same ALS, so getCurrentScope/getIsolationScope/getActiveSpan resolve to the scope carrying our span.\n // 4. Nest: any child span started in the traced op parents to that active span.\n channel.start.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n // Stash the caller's store before we swap in the span store, so `asyncStart` can restore it for\n // callback-style channels (see `_sentryCallerStore`).\n data._sentryCallerStore = asyncLocalStorage.getStore();\n\n const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return data._sentryCallerStore as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n // Restore the caller's context for the async continuation. Only callback-style channels `runStores`\n // `asyncStart` (so the callback runs inside this store). promise channels `publish` it, leaving this\n // inert, their continuation already inherits the caller's context natively.\n channel.asyncStart.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n return data._sentryCallerStore as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the stores\n channel.start.unbindStore(asyncLocalStorage);\n channel.asyncStart.unbindStore(asyncLocalStorage);\n },\n };\n}\n\nfunction endBoundSpan<TData extends object>(\n data: TracingChannelPayloadWithSpan<TData>,\n beforeSpanEnd: TracingChannelLifeCycleOptions<TData>['beforeSpanEnd'],\n): void {\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n beforeSpanEnd?.(span, data);\n span.end();\n}\n\ntype ErrorInfo = {\n message: string | undefined;\n attributes: Record<string, string>;\n};\n\n/**\n * Best-effort message and attribute extraction for thrown/rejected values.\n */\nfunction getErrorInfo(error: unknown): ErrorInfo {\n const isObject = !!error && typeof error === 'object';\n const raw = isObject ? ('message' in error ? error.message : undefined) : error;\n\n // Leave the status message unset if not set (e.g. an `AggregateError` from\n // ECONNREFUSED, whose `.message` is empty). Otherwise cast to string.\n const message = raw ? String(raw) : undefined;\n const type = isObject && 'name' in error ? String(error.name) : 'unknown';\n\n return {\n message,\n attributes: {\n [ERROR_TYPE]: type,\n },\n };\n}\n"],"names":["captureException","SPAN_STATUS_ERROR","getAsyncContextStrategy","getMainCarrier","DEBUG_BUILD","debug","ERROR_TYPE"],"mappings":"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"} |
@@ -20,3 +20,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const toolDescriptionsByCallId = /* @__PURE__ */ new Map(); | ||
| const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "rerank"]); | ||
| const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "embedMany", "rerank"]); | ||
| function clearOperationId(data) { | ||
@@ -28,6 +28,9 @@ if (!ROOT_OPERATION_TYPES.has(data.type)) { | ||
| if (callId) { | ||
| operationIdByCallId.delete(callId); | ||
| toolDescriptionsByCallId.delete(callId); | ||
| clearOperationCallId(callId); | ||
| } | ||
| } | ||
| function clearOperationCallId(callId) { | ||
| operationIdByCallId.delete(callId); | ||
| toolDescriptionsByCallId.delete(callId); | ||
| } | ||
| function recordToolDescriptions(callId, tools) { | ||
@@ -112,6 +115,9 @@ if (!callId || !Array.isArray(tools)) { | ||
| case "embed": | ||
| case "embedMany": { | ||
| const input = type === "embedMany" ? event.values : event.value; | ||
| return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, { | ||
| ...baseAttributes, | ||
| ...recordInputs && event.value !== void 0 ? { [attributes.GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {} | ||
| ...recordInputs && input !== void 0 ? { [attributes.GEN_AI_EMBEDDINGS_INPUT]: safeStringify(input) } : {} | ||
| }); | ||
| } | ||
| case "rerank": | ||
@@ -361,2 +367,3 @@ return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes); | ||
| exports.clearOperationCallId = clearOperationCallId; | ||
| exports.clearOperationId = clearOperationId; | ||
@@ -363,0 +370,0 @@ exports.createSpanFromMessage = createSpanFromMessage; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n }\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\ntype VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\ninterface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && event.value !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}),\n });\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":["tracingChannel","bindTracingChannelToSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_SYSTEM","GEN_AI_REQUEST_MODEL","GEN_AI_EMBEDDINGS_INPUT","attributes","startInactiveSpan","GEN_AI_OPERATION_NAME","GEN_AI_INVOKE_AGENT_SPAN_OP","GEN_AI_RESPONSE_STREAMING","GEN_AI_FUNCTION_ID","GEN_AI_REQUEST_AVAILABLE_TOOLS","GEN_AI_EXECUTE_TOOL_SPAN_OP","GEN_AI_TOOL_TYPE","GEN_AI_TOOL_NAME","GEN_AI_TOOL_INPUT","GEN_AI_TOOL_OUTPUT","GEN_AI_USAGE_INPUT_TOKENS","GEN_AI_USAGE_OUTPUT_TOKENS","GEN_AI_USAGE_TOTAL_TOKENS","GEN_AI_RESPONSE_FINISH_REASONS","GEN_AI_RESPONSE_ID","GEN_AI_RESPONSE_MODEL","getProviderMetadataAttributes","GEN_AI_CONVERSATION_ID_ATTRIBUTE","spanToJSON","GEN_AI_OUTPUT_MESSAGES","SPAN_STATUS_ERROR","withScope","spanToTraceContext","captureException","getClient","shouldEnableTruncation","GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE","GEN_AI_INPUT_MESSAGES","getTruncatedJsonString","GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE"],"mappings":"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"} | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'embedMany', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n clearOperationCallId(callId);\n }\n}\n\n/**\n * Drop the per-operation `callId` maps for a single id. The v6 orchestrion adapter uses this to clear a\n * `streamText` operation only after its lazily-run model call settles — the operation's own span ends\n * synchronously (when `streamText` returns) but the model call runs later as the stream is consumed, and\n * it still needs the operation's `operationId`/`isStream` entry to name itself `ai.streamText.doStream`.\n */\nexport function clearOperationCallId(callId: string): void {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'embedMany'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\nexport type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\nexport interface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n case 'embedMany': {\n // `embed` carries a single `value`; `embedMany` a `values` array — both map to the embeddings input.\n const input = type === 'embedMany' ? event.values : event.value;\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && input !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(input) } : {}),\n });\n }\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":["tracingChannel","bindTracingChannelToSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","GEN_AI_SYSTEM","GEN_AI_REQUEST_MODEL","GEN_AI_EMBEDDINGS_INPUT","attributes","startInactiveSpan","GEN_AI_OPERATION_NAME","GEN_AI_INVOKE_AGENT_SPAN_OP","GEN_AI_RESPONSE_STREAMING","GEN_AI_FUNCTION_ID","GEN_AI_REQUEST_AVAILABLE_TOOLS","GEN_AI_EXECUTE_TOOL_SPAN_OP","GEN_AI_TOOL_TYPE","GEN_AI_TOOL_NAME","GEN_AI_TOOL_INPUT","GEN_AI_TOOL_OUTPUT","GEN_AI_USAGE_INPUT_TOKENS","GEN_AI_USAGE_OUTPUT_TOKENS","GEN_AI_USAGE_TOTAL_TOKENS","GEN_AI_RESPONSE_FINISH_REASONS","GEN_AI_RESPONSE_ID","GEN_AI_RESPONSE_MODEL","getProviderMetadataAttributes","GEN_AI_CONVERSATION_ID_ATTRIBUTE","spanToJSON","GEN_AI_OUTPUT_MESSAGES","SPAN_STATUS_ERROR","withScope","spanToTraceContext","captureException","getClient","shouldEnableTruncation","GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE","GEN_AI_INPUT_MESSAGES","getTruncatedJsonString","GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE"],"mappings":"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"} |
@@ -0,2 +1,4 @@ | ||
| export { mongooseIntegration } from './mongoose/index.js'; | ||
| export { IOREDIS_DC_CHANNEL_COMMAND, IOREDIS_DC_CHANNEL_CONNECT, REDIS_DC_CHANNEL_BATCH, REDIS_DC_CHANNEL_COMMAND, REDIS_DC_CHANNEL_CONNECT, subscribeRedisDiagnosticChannels } from './redis/redis-dc-subscriber.js'; | ||
| export { defaultDbStatementSerializer } from './redis/redis-statement-serializer.js'; | ||
| export { bindTracingChannelToSpan } from './tracing-channel.js'; | ||
@@ -3,0 +5,0 @@ export { vercelAiIntegration } from './vercel-ai/index.js'; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, debug, waitForTracingChannelBinding, bindScopeToEmitter, getCurrentScope, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; | ||
| import { defineIntegration, debug, waitForTracingChannelBinding, getCurrentScope, startInactiveSpan, SPAN_KIND, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, bindScopeToEmitter } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
@@ -34,2 +34,3 @@ import { CHANNELS } from '../../orchestrion/channels.js'; | ||
| name: sql ?? "mysql.query", | ||
| kind: SPAN_KIND.CLIENT, | ||
| op: "db", | ||
@@ -36,0 +37,0 @@ attributes: { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql' as const;\n\n// OTel \"OLD\" db/net semantic-conventions, inlined to keep this integration free of OTel deps. Matches\n// `@opentelemetry/instrumentation-mysql`'s default and the SDK's `inferDbSpanData` (which renames spans\n// off `db.statement`).\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context` object. Documented here\n * rather than imported because orchestrion's runtime doesn't export it.\n */\ninterface MysqlQueryChannelContext {\n // The live args array passed to the wrapped `connection.query` call; `arguments[0]` is the SQL.\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto the streamed `Query` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<MysqlQueryChannelContext>(CHANNELS.MYSQL_QUERY),\n data => {\n const sql = extractSql(data.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(data.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n // For the streamed path: mysql emits the `Query` emitter's events from its socket data\n // handler with the caller's context lost. `deferSpanEnd` replays this scope onto the emitter.\n data._sentryCallerScope = getCurrentScope();\n\n return startInactiveSpan({\n name: sql ?? 'mysql.query',\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n },\n {\n // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the\n // emitter's `'end'`/`'error'`, not the channel, so defer ending to those.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope so user listeners on the emitter nest under it, not a new trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n },\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"mysql.js","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn, Scope } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_KIND,\n startInactiveSpan,\n waitForTracingChannelBinding,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\nimport { bindTracingChannelToSpan } from '../../tracing-channel';\n\n// NOTE: this uses the same name as the OTel integration by design.\n// When enabled, OTel 'Mysql' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'Mysql' as const;\n\n// OTel \"OLD\" db/net semantic-conventions, inlined to keep this integration free of OTel deps. Matches\n// `@opentelemetry/instrumentation-mysql`'s default and the SDK's `inferDbSpanData` (which renames spans\n// off `db.statement`).\nconst ATTR_DB_SYSTEM = 'db.system';\nconst ATTR_DB_CONNECTION_STRING = 'db.connection_string';\nconst ATTR_DB_NAME = 'db.name';\nconst ATTR_DB_USER = 'db.user';\nconst ATTR_DB_STATEMENT = 'db.statement';\nconst ATTR_NET_PEER_NAME = 'net.peer.name';\nconst ATTR_NET_PEER_PORT = 'net.peer.port';\n\n/**\n * The shape orchestrion's transform attaches to the tracing-channel `context` object. Documented here\n * rather than imported because orchestrion's runtime doesn't export it.\n */\ninterface MysqlQueryChannelContext {\n // The live args array passed to the wrapped `connection.query` call; `arguments[0]` is the SQL.\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\n // The caller's scope, captured at `start` and replayed onto the streamed `Query` emitter (see below).\n _sentryCallerScope?: Scope;\n}\n\ninterface MysqlConnectionConfig {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n // Pool connections nest the real config one level deeper.\n connectionConfig?: MysqlConnectionConfig;\n}\n\ninterface MysqlConnection {\n config?: MysqlConnectionConfig;\n}\n\nconst _mysqlChannelIntegration = (() => {\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n // `tracingChannel` is unavailable before Node 18.19 so do nothing in that case.\n if (!diagnosticsChannel.tracingChannel) {\n return;\n }\n\n DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<MysqlQueryChannelContext>(CHANNELS.MYSQL_QUERY),\n data => {\n const sql = extractSql(data.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(data.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n // For the streamed path: mysql emits the `Query` emitter's events from its socket data\n // handler with the caller's context lost. `deferSpanEnd` replays this scope onto the emitter.\n data._sentryCallerScope = getCurrentScope();\n\n return startInactiveSpan({\n name: sql ?? 'mysql.query',\n kind: SPAN_KIND.CLIENT,\n op: 'db',\n attributes: {\n [ATTR_DB_SYSTEM]: 'mysql',\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.db.orchestrion.mysql',\n [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : undefined, database),\n ...(database ? { [ATTR_DB_NAME]: database } : {}),\n ...(user ? { [ATTR_DB_USER]: user } : {}),\n ...(sql ? { [ATTR_DB_STATEMENT]: sql } : {}),\n ...(host ? { [ATTR_NET_PEER_NAME]: host } : {}),\n ...(portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {}),\n },\n });\n },\n {\n // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the\n // emitter's `'end'`/`'error'`, not the channel, so defer ending to those.\n deferSpanEnd({ data, end }) {\n const result = data.result;\n if (!result || typeof result !== 'object' || !hasOnMethod(result)) {\n return false;\n }\n\n // Replay the caller's scope so user listeners on the emitter nest under it, not a new trace.\n const callerScope = data._sentryCallerScope;\n if (callerScope) {\n bindScopeToEmitter(result, callerScope);\n }\n\n result.on('error', err => end(err));\n result.on('end', () => end());\n\n return true;\n },\n },\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\nfunction hasOnMethod(obj: object): obj is { on: (event: string, listener: (arg?: unknown) => void) => unknown } {\n return 'on' in obj && typeof (obj as { on?: unknown }).on === 'function';\n}\n\nfunction extractSql(firstArg: unknown): string | undefined {\n if (typeof firstArg === 'string') {\n return firstArg;\n }\n if (firstArg && typeof firstArg === 'object' && 'sql' in firstArg) {\n const sql = (firstArg as { sql?: unknown }).sql;\n return typeof sql === 'string' ? sql : undefined;\n }\n return undefined;\n}\n\nfunction getConnectionConfig(connection: MysqlConnection | undefined): {\n host?: string;\n port?: number | string;\n database?: string;\n user?: string;\n} {\n // Pool connections nest the real config under `.connectionConfig`; single\n // connections expose it directly. Matches `@opentelemetry/instrumentation-mysql`.\n const config = connection?.config?.connectionConfig ?? connection?.config ?? {};\n return {\n host: config.host,\n port: config.port,\n database: config.database,\n user: config.user,\n };\n}\n\nfunction getJDBCString(host: string | undefined, port: number | undefined, database: string | undefined): string {\n let s = `jdbc:mysql://${host || 'localhost'}`;\n if (typeof port === 'number') {\n s += `:${port}`;\n }\n if (database) {\n s += `/${database}`;\n }\n return s;\n}\n\n/**\n * EXPERIMENTAL — orchestrion-driven mysql integration.\n *\n * Subscribes to the `orchestrion:mysql:query` diagnostics_channel that the\n * orchestrion code transform injects into `mysql/lib/Connection.js`'s\n * `Connection.prototype.query`. Requires the orchestrion runtime hook or\n * bundler plugin to be active — wire that up via `_experimentalSetupOrchestrion`.\n */\nexport const mysqlChannelIntegration = defineIntegration(_mysqlChannelIntegration);\n"],"names":[],"mappings":"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"} |
| import codeTransformer from '@apm-js-collab/code-transformer-bundler-plugins/vite'; | ||
| import MagicString from 'magic-string'; | ||
| import { SENTRY_INSTRUMENTATIONS, INSTRUMENTED_MODULE_NAMES } from '../config.js'; | ||
| import { SENTRY_INSTRUMENTATIONS, INSTRUMENTED_MODULE_NAMES } from '../config/index.js'; | ||
@@ -5,0 +5,0 @@ function sentryOrchestrionPlugin() { |
@@ -0,4 +1,19 @@ | ||
| import { mysqlChannels } from './config/mysql.js'; | ||
| import { lruMemoizerChannels } from './config/lru-memoizer.js'; | ||
| import { ioredisChannels } from './config/ioredis.js'; | ||
| import { pgChannels } from './config/pg.js'; | ||
| import { openaiChannels } from './config/openai.js'; | ||
| import { anthropicAiChannels } from './config/anthropic-ai.js'; | ||
| import { vercelAiChannels } from './config/vercel-ai.js'; | ||
| import { hapiChannels } from './config/hapi.js'; | ||
| const CHANNELS = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query", | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| ...mysqlChannels, | ||
| ...lruMemoizerChannels, | ||
| ...ioredisChannels, | ||
| ...pgChannels, | ||
| ...openaiChannels, | ||
| ...anthropicAiChannels, | ||
| ...vercelAiChannels, | ||
| ...hapiChannels | ||
| }; | ||
@@ -5,0 +20,0 @@ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"channels.js","sources":["../../../src/orchestrion/channels.ts"],"sourcesContent":["/**\n * Fully-qualified `diagnostics_channel` names that orchestrion publishes to.\n *\n * Orchestrion's transform always prefixes the configured `channelName` with\n * `orchestrion:${module.name}:`. So a config of\n * `{ channelName: 'query', module: { name: 'mysql' } }`\n * publishes to `orchestrion:mysql:query`.\n *\n * Subscribers (`integrations/<lib>/tracing-channel.ts`) consume the full\n * prefixed string from this map; the config files set only the unprefixed\n * suffix in `channelName`. Keeping both pieces in one file is what guarantees\n * they don't drift apart and silently stop firing.\n */\nexport const CHANNELS = {\n MYSQL_QUERY: 'orchestrion:mysql:query',\n LRU_MEMOIZER_LOAD: 'orchestrion:lru-memoizer:load',\n} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":[],"mappings":"AAaO,MAAM,QAAA,GAAW;AAAA,EACtB,WAAA,EAAa,yBAAA;AAAA,EACb,iBAAA,EAAmB;AACrB;;;;"} | ||
| {"version":3,"file":"channels.js","sources":["../../../src/orchestrion/channels.ts"],"sourcesContent":["import { mysqlChannels } from './config/mysql';\nimport { lruMemoizerChannels } from './config/lru-memoizer';\nimport { ioredisChannels } from './config/ioredis';\nimport { pgChannels } from './config/pg';\nimport { openaiChannels } from './config/openai';\nimport { anthropicAiChannels } from './config/anthropic-ai';\nimport { vercelAiChannels } from './config/vercel-ai';\nimport { hapiChannels } from './config/hapi';\n\n/**\n * Fully-qualified `diagnostics_channel` names that orchestrion publishes to.\n *\n * Orchestrion's transform always prefixes the configured `channelName` with\n * `orchestrion:${module.name}:`. So a config of\n * `{ channelName: 'query', module: { name: 'mysql' } }`\n * publishes to `orchestrion:mysql:query`.\n *\n * Subscribers (`integrations/<lib>/tracing-channel.ts`) consume the full\n * prefixed string from this map; the config files set only the unprefixed\n * suffix in `channelName`. Keeping both pieces in one file is what guarantees\n * they don't drift apart and silently stop firing.\n */\nexport const CHANNELS = {\n ...mysqlChannels,\n ...lruMemoizerChannels,\n ...ioredisChannels,\n ...pgChannels,\n ...openaiChannels,\n ...anthropicAiChannels,\n ...vercelAiChannels,\n ...hapiChannels,\n} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":[],"mappings":";;;;;;;;;AAsBO,MAAM,QAAA,GAAW;AAAA,EACtB,GAAG,aAAA;AAAA,EACH,GAAG,mBAAA;AAAA,EACH,GAAG,eAAA;AAAA,EACH,GAAG,UAAA;AAAA,EACH,GAAG,cAAA;AAAA,EACH,GAAG,mBAAA;AAAA,EACH,GAAG,gBAAA;AAAA,EACH,GAAG;AACL;;;;"} |
| import { debug } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../debug-build.js'; | ||
| function isOrchestrionInjected() { | ||
| const marker = globalThis.__SENTRY_ORCHESTRION__; | ||
| return !!(marker?.runtime || marker?.bundler); | ||
| } | ||
| function detectOrchestrionSetup() { | ||
@@ -10,3 +14,3 @@ if (!DEBUG_BUILD) return; | ||
| DEBUG_BUILD && debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`); | ||
| if (!runtime && !bundler) { | ||
| if (!isOrchestrionInjected()) { | ||
| DEBUG_BUILD && debug.warn( | ||
@@ -18,3 +22,3 @@ "[Sentry] No diagnostics-channel injection detected. Channel-based integrations (mysql, \u2026) will not record spans. Make sure the diagnostics channels are injected via the runtime `--import` hook or a bundler plugin before the instrumented modules load." | ||
| export { detectOrchestrionSetup }; | ||
| export { detectOrchestrionSetup, isOrchestrionInjected }; | ||
| //# sourceMappingURL=detect.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"detect.js","sources":["../../../src/orchestrion/detect.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Verifies that the diagnostics channels have been injected either by the\n * runtime `--import` hook (or init-time registration), a bundler plugin, or\n * both, and warns if not.\n *\n * Both injectors being active at once is fine: they operate on disjoint module\n * sets (a module is either loaded through Node's loader and transformed by the\n * runtime hook, or inlined by the bundler and transformed by the plugin), so\n * a single module can't be double-wrapped. A hybrid setup, with some deps\n * external and runtime-instrumented, others bundled and plugin-instrumented,\n * is fine.\n *\n * Note: intentionally does NOT warn in production, only in debug builds,\n * because production warnings are reserved for truly critical issues.\n */\nexport function detectOrchestrionSetup(): void {\n if (!DEBUG_BUILD) return;\n\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n const runtime = !!marker?.runtime;\n const bundler = !!marker?.bundler;\n\n DEBUG_BUILD && debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`);\n\n if (!runtime && !bundler) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] No diagnostics-channel injection detected. Channel-based integrations ' +\n '(mysql, …) will not record spans. Make sure the diagnostics channels are injected ' +\n 'via the runtime `--import` hook or a bundler plugin before the instrumented modules load.',\n );\n }\n}\n"],"names":[],"mappings":";;;AAuBO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,CAAC,WAAA,EAAa;AAElB,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAE1B,EAAA,WAAA,IAAe,MAAM,GAAA,CAAI,CAAA,8BAAA,EAAiC,OAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAEtF,EAAA,IAAI,CAAC,OAAA,IAAW,CAAC,OAAA,EAAS;AACxB,IAAA,WAAA,IACE,KAAA,CAAM,IAAA;AAAA,MACJ;AAAA,KAGF;AAAA,EACJ;AACF;;;;"} | ||
| {"version":3,"file":"detect.js","sources":["../../../src/orchestrion/detect.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { DEBUG_BUILD } from '../debug-build';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Whether orchestrion has injected the diagnostics channels into this process,\n * either by the runtime `--import` hook / init-time registration (`runtime`)\n * or a bundler plugin (`bundler`). Both injectors set a flag on the\n * `globalThis.__SENTRY_ORCHESTRION__` marker.\n *\n * Use this to avoid wiring up channel-subscriber integrations when nothing\n * will ever publish to those channels.\n */\nexport function isOrchestrionInjected(): boolean {\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n return !!(marker?.runtime || marker?.bundler);\n}\n\n/**\n * Verifies that the diagnostics channels have been injected either by the\n * runtime `--import` hook (or init-time registration), a bundler plugin, or\n * both, and warns if not.\n *\n * Both injectors being active at once is fine: they operate on disjoint module\n * sets (a module is either loaded through Node's loader and transformed by the\n * runtime hook, or inlined by the bundler and transformed by the plugin), so\n * a single module can't be double-wrapped. A hybrid setup, with some deps\n * external and runtime-instrumented, others bundled and plugin-instrumented,\n * is fine.\n *\n * Note: intentionally does NOT warn in production, only in debug builds,\n * because production warnings are reserved for truly critical issues.\n */\nexport function detectOrchestrionSetup(): void {\n if (!DEBUG_BUILD) return;\n\n const marker = globalThis.__SENTRY_ORCHESTRION__;\n const runtime = !!marker?.runtime;\n const bundler = !!marker?.bundler;\n\n DEBUG_BUILD && debug.log(`[orchestrion] detect: runtime=${runtime} bundler=${bundler}`);\n\n if (!isOrchestrionInjected()) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] No diagnostics-channel injection detected. Channel-based integrations ' +\n '(mysql, …) will not record spans. Make sure the diagnostics channels are injected ' +\n 'via the runtime `--import` hook or a bundler plugin before the instrumented modules load.',\n );\n }\n}\n"],"names":[],"mappings":";;;AAiBO,SAAS,qBAAA,GAAiC;AAC/C,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,OAAO,CAAC,EAAE,MAAA,EAAQ,OAAA,IAAW,MAAA,EAAQ,OAAA,CAAA;AACvC;AAiBO,SAAS,sBAAA,GAA+B;AAC7C,EAAA,IAAI,CAAC,WAAA,EAAa;AAElB,EAAA,MAAM,SAAS,UAAA,CAAW,sBAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAC1B,EAAA,MAAM,OAAA,GAAU,CAAC,CAAC,MAAA,EAAQ,OAAA;AAE1B,EAAA,WAAA,IAAe,MAAM,GAAA,CAAI,CAAA,8BAAA,EAAiC,OAAO,CAAA,SAAA,EAAY,OAAO,CAAA,CAAE,CAAA;AAEtF,EAAA,IAAI,CAAC,uBAAsB,EAAG;AAC5B,IAAA,WAAA,IACE,KAAA,CAAM,IAAA;AAAA,MACJ;AAAA,KAGF;AAAA,EACJ;AACF;;;;"} |
@@ -1,4 +0,22 @@ | ||
| export { detectOrchestrionSetup } from './detect.js'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql.js'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer.js'; | ||
| import { anthropicChannelIntegration } from '../integrations/tracing-channel/anthropic.js'; | ||
| import { hapiChannelIntegration } from '../integrations/tracing-channel/hapi.js'; | ||
| export { ioredisChannelIntegration } from '../integrations/tracing-channel/ioredis.js'; | ||
| import { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer.js'; | ||
| import { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql.js'; | ||
| import { openaiChannelIntegration } from '../integrations/tracing-channel/openai.js'; | ||
| import { postgresChannelIntegration } from '../integrations/tracing-channel/postgres.js'; | ||
| import { vercelAiChannelIntegration } from '../integrations/tracing-channel/vercel-ai.js'; | ||
| export { detectOrchestrionSetup, isOrchestrionInjected } from './detect.js'; | ||
| const channelIntegrations = { | ||
| postgresIntegration: postgresChannelIntegration, | ||
| mysqlIntegration: mysqlChannelIntegration, | ||
| lruMemoizerIntegration: lruMemoizerChannelIntegration, | ||
| openaiIntegration: openaiChannelIntegration, | ||
| anthropicIntegration: anthropicChannelIntegration, | ||
| vercelAiIntegration: vercelAiChannelIntegration, | ||
| hapiIntegration: hapiChannelIntegration | ||
| }; | ||
| export { anthropicChannelIntegration, channelIntegrations, hapiChannelIntegration, lruMemoizerChannelIntegration, mysqlChannelIntegration, openaiChannelIntegration, postgresChannelIntegration, vercelAiChannelIntegration }; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"} | ||
| {"version":3,"file":"index.js","sources":["../../../src/orchestrion/index.ts"],"sourcesContent":["import { anthropicChannelIntegration } from '../integrations/tracing-channel/anthropic';\nimport { hapiChannelIntegration } from '../integrations/tracing-channel/hapi';\nimport { ioredisChannelIntegration } from '../integrations/tracing-channel/ioredis';\nimport { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer';\nimport { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql';\nimport { openaiChannelIntegration } from '../integrations/tracing-channel/openai';\nimport { postgresChannelIntegration } from '../integrations/tracing-channel/postgres';\nimport { vercelAiChannelIntegration } from '../integrations/tracing-channel/vercel-ai';\n\nexport { detectOrchestrionSetup, isOrchestrionInjected } from './detect';\nexport {\n anthropicChannelIntegration,\n hapiChannelIntegration,\n ioredisChannelIntegration,\n lruMemoizerChannelIntegration,\n mysqlChannelIntegration,\n openaiChannelIntegration,\n postgresChannelIntegration,\n vercelAiChannelIntegration,\n};\nexport type { IORedisChannelIntegrationOptions, IORedisResponseHook } from '../integrations/tracing-channel/ioredis';\n\n/**\n * The canonical set of orchestrion diagnostics-channel integrations, keyed by their public\n * (OTel-parity) factory name.\n *\n * Single source of truth: add a new channel integration here and every consumer — the `@sentry/node`\n * opt-in helper (`experimentalUseDiagnosticsChannelInjection`) and its public\n * `diagnosticsChannelInjectionIntegrations()` map — picks it up automatically, so there's no separate\n * list to keep in sync.\n *\n * NOTE: `ioredisChannelIntegration` is intentionally NOT here. It only partially replaces the\n * composite OTel `Redis` integration and needs the node SDK's redis cache `responseHook` (which\n * can't live in `server-utils`), so `@sentry/node` wires it up separately.\n */\nexport const channelIntegrations = {\n postgresIntegration: postgresChannelIntegration,\n mysqlIntegration: mysqlChannelIntegration,\n lruMemoizerIntegration: lruMemoizerChannelIntegration,\n openaiIntegration: openaiChannelIntegration,\n anthropicIntegration: anthropicChannelIntegration,\n vercelAiIntegration: vercelAiChannelIntegration,\n hapiIntegration: hapiChannelIntegration,\n} as const;\n"],"names":[],"mappings":";;;;;;;;;;AAmCO,MAAM,mBAAA,GAAsB;AAAA,EACjC,mBAAA,EAAqB,0BAAA;AAAA,EACrB,gBAAA,EAAkB,uBAAA;AAAA,EAClB,sBAAA,EAAwB,6BAAA;AAAA,EACxB,iBAAA,EAAmB,wBAAA;AAAA,EACnB,oBAAA,EAAsB,2BAAA;AAAA,EACtB,mBAAA,EAAqB,0BAAA;AAAA,EACrB,eAAA,EAAiB;AACnB;;;;"} |
| import { debug } from '@sentry/core'; | ||
| import * as Module from 'node:module'; | ||
| import { createRequire } from 'node:module'; | ||
| import { pathToFileURL } from 'node:url'; | ||
| import 'node:url'; | ||
| import { DEBUG_BUILD } from '../../debug-build.js'; | ||
| import { SENTRY_INSTRUMENTATIONS } from '../config.js'; | ||
| import { SENTRY_INSTRUMENTATIONS } from '../config/index.js'; | ||
@@ -18,3 +18,4 @@ function registerDiagnosticsChannelInjection() { | ||
| const stableSyncHooks = (nodeVersion[0] ?? 0) > 25 || nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1 || nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13 || (denoVersion[0] ?? 0) > 2 || denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8; | ||
| const nodeRequire = typeof require === "function" ? require : createRequire(import.meta.url); | ||
| let nodeRequire; | ||
| nodeRequire = createRequire(import.meta.url); | ||
| const mod = Module; | ||
@@ -28,3 +29,6 @@ try { | ||
| } else if (typeof mod.register === "function" && !globalAny.Bun && !globalAny.Deno) { | ||
| mod.register(pathToFileURL(nodeRequire.resolve("@apm-js-collab/tracing-hooks/hook.mjs")).href, { | ||
| let parentURL; | ||
| parentURL = import.meta.url; | ||
| mod.register("@apm-js-collab/tracing-hooks/hook.mjs", { | ||
| parentURL, | ||
| data: { instrumentations: SENTRY_INSTRUMENTATIONS } | ||
@@ -31,0 +35,0 @@ }); |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"register.js","sources":["../../../../src/orchestrion/runtime/register.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { createRequire } from 'node:module';\nimport * as Module from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { SENTRY_INSTRUMENTATIONS } from '../config';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Synchronously register the diagnostics-channel injection module hooks.\n *\n * This is the single source of truth for the registration logic. It is used by:\n * - `Sentry.init()` (the Node SDK calls it directly — that's why this module\n * must be CJS-compatible / dual-built, so it can be `require()`d synchronously\n * before the app's `import`s resolve), and\n * - `import-hook.mjs`, the side-effecting `--import` entry, which just calls it.\n *\n * Libraries imported *after* this call publish the `tracingChannel` events that\n * the channel-based integrations subscribe to.\n *\n * Idempotent via `globalThis.__SENTRY_ORCHESTRION__` — a no-op if the runtime\n * `--import` hook or a bundler plugin already injected the channels.\n */\nexport function registerDiagnosticsChannelInjection(): void {\n const g = (globalThis.__SENTRY_ORCHESTRION__ ??= {});\n\n // Already injected (runtime --import hook or bundler plugin) — nothing to do.\n if (g.runtime || g.bundler) {\n return;\n }\n\n const globalAny = globalThis as { Bun?: unknown; Deno?: { version?: { deno?: string } } };\n const parseVersion = (v: string): number[] => v.split('.').map(n => parseInt(n, 10));\n const nodeVersion = parseVersion(process.versions.node ?? '0.0.0');\n const denoVersion = parseVersion(globalAny.Deno?.version?.deno ?? '0.0.0');\n // `Module.registerHooks` only became stable in Node 24.13 / 25.1 and Deno 2.8.\n const stableSyncHooks =\n (nodeVersion[0] ?? 0) > 25 ||\n (nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1) ||\n (nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13) ||\n (denoVersion[0] ?? 0) > 2 ||\n (denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8);\n\n // Prefer the builtin `require` if possible. This is present in CommonJS,\n // including a bundler's CJS output, so no need to ever have to evaluate\n // `import.meta.url` there.\n //\n // esbuild and friends rewrite `import.meta.url` to `{}` for CJS output,\n // which would make `createRequire(undefined)` throw.\n // Only use `import.meta.url` in true ESM, where there's no `require`\n const nodeRequire = typeof require === 'function' ? require : createRequire(import.meta.url);\n\n // `Module.registerHooks` / `Module.register` are newer than the @types/node\n // we build against, hence the cast.\n const mod = Module as unknown as {\n registerHooks?: (hooks: unknown) => void;\n register?: (specifier: string, options: unknown) => void;\n };\n\n // runs both at `--import` time and (synchronously) inside `Sentry.init()`,\n // so an unguarded throw would either abort startup or make `init()` throw.\n // On any failure (e.g. dep resolution, `require(esm)` / Node-compat\n // incompatibility) we warn (DEBUG only) and continue without channel\n // injection\n try {\n if (typeof mod.registerHooks === 'function' && stableSyncHooks) {\n // Sync hooks cover CJS and ESM, no separate `_compile` patch needed.\n // We require() the module here so that we can synchronously load it,\n // including from a CommonJS Sentry build, without bundlers pulling in.\n // All versions in stableSyncHooks support this.\n const { initialize, resolve, load } = nodeRequire('@apm-js-collab/tracing-hooks/hook-sync.mjs') as {\n initialize: (opts: { instrumentations: unknown }) => void;\n resolve: unknown;\n load: unknown;\n };\n initialize({ instrumentations: SENTRY_INSTRUMENTATIONS });\n mod.registerHooks({ resolve, load });\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.registerHooks()');\n } else if (typeof mod.register === 'function' && !globalAny.Bun && !globalAny.Deno) {\n // `Module.register` + the `_compile` patch is Node 18.19–24.12 / 25.0\n // path. Bun/Deno are excluded: they don't support this combination and\n // must use the stable `registerHooks` path above (or none at all).\n // Resolve the hook to an absolute file URL ourselves so\n // `Module.register` needs no `parentURL`, so no need for\n // `import.meta.url` polyfilling\n mod.register(pathToFileURL(nodeRequire.resolve('@apm-js-collab/tracing-hooks/hook.mjs')).href, {\n data: { instrumentations: SENTRY_INSTRUMENTATIONS },\n });\n\n // ALSO patch `Module.prototype._compile` for the CJS side: when an ESM\n // file `import`s a CJS package, the package's internal `require()` calls\n // are resolved through the CJS machinery and never reach the ESM\n // register hook, so without this patch the file we want to instrument\n // loads untransformed.\n const ModulePatch = nodeRequire('@apm-js-collab/tracing-hooks') as new (opts: { instrumentations: unknown }) => {\n patch: () => void;\n };\n new ModulePatch({ instrumentations: SENTRY_INSTRUMENTATIONS }).patch();\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.register()');\n } else {\n DEBUG_BUILD &&\n debug.warn('[Sentry] No available Node API to register diagnostics-channel injection hooks; skipping.');\n return;\n }\n } catch (error) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] Failed to register diagnostics-channel injection hooks; channel-based integrations ' +\n 'will not record spans.',\n error,\n );\n return;\n }\n\n g.runtime = true;\n}\n"],"names":[],"mappings":";;;;;;;AA2BO,SAAS,mCAAA,GAA4C;AAC1D,EAAA,MAAM,CAAA,GAAK,UAAA,CAAW,sBAAA,KAAX,UAAA,CAAW,yBAA2B,EAAC,CAAA;AAGlD,EAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,EAAS;AAC1B,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAwB,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AACnF,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,QAAQ,OAAO,CAAA;AACjE,EAAA,MAAM,cAAc,YAAA,CAAa,SAAA,CAAU,IAAA,EAAM,OAAA,EAAS,QAAQ,OAAO,CAAA;AAEzE,EAAA,MAAM,mBACH,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,MACvB,WAAA,CAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,YAAY,CAAC,CAAA,IAAK,CAAA,KAAM,CAAA,IAClD,YAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,KAAM,EAAA,IAAA,CAClD,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,IACvB,WAAA,CAAY,CAAC,CAAA,KAAM,CAAA,IAAA,CAAM,WAAA,CAAY,CAAC,KAAK,CAAA,KAAM,CAAA;AASpD,EAAA,MAAM,cAAc,OAAO,OAAA,KAAY,aAAa,OAAA,GAAU,aAAA,CAAc,YAAY,GAAG,CAAA;AAI3F,EAAA,MAAM,GAAA,GAAM,MAAA;AAUZ,EAAA,IAAI;AACF,IAAA,IAAI,OAAO,GAAA,CAAI,aAAA,KAAkB,UAAA,IAAc,eAAA,EAAiB;AAK9D,MAAA,MAAM,EAAE,UAAA,EAAY,OAAA,EAAS,IAAA,EAAK,GAAI,YAAY,4CAA4C,CAAA;AAK9F,MAAA,UAAA,CAAW,EAAE,gBAAA,EAAkB,uBAAA,EAAyB,CAAA;AACxD,MAAA,GAAA,CAAI,aAAA,CAAc,EAAE,OAAA,EAAS,IAAA,EAAM,CAAA;AACnC,MAAA,WAAA,IAAe,KAAA,CAAM,IAAI,mFAAmF,CAAA;AAAA,IAC9G,CAAA,MAAA,IAAW,OAAO,GAAA,CAAI,QAAA,KAAa,UAAA,IAAc,CAAC,SAAA,CAAU,GAAA,IAAO,CAAC,SAAA,CAAU,IAAA,EAAM;AAOlF,MAAA,GAAA,CAAI,SAAS,aAAA,CAAc,WAAA,CAAY,QAAQ,uCAAuC,CAAC,EAAE,IAAA,EAAM;AAAA,QAC7F,IAAA,EAAM,EAAE,gBAAA,EAAkB,uBAAA;AAAwB,OACnD,CAAA;AAOD,MAAA,MAAM,WAAA,GAAc,YAAY,8BAA8B,CAAA;AAG9D,MAAA,IAAI,YAAY,EAAE,gBAAA,EAAkB,uBAAA,EAAyB,EAAE,KAAA,EAAM;AACrE,MAAA,WAAA,IAAe,KAAA,CAAM,IAAI,8EAA8E,CAAA;AAAA,IACzG,CAAA,MAAO;AACL,MAAA,WAAA,IACE,KAAA,CAAM,KAAK,2FAA2F,CAAA;AACxG,MAAA;AAAA,IACF;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,WAAA,IACE,KAAA,CAAM,IAAA;AAAA,MACJ,oHAAA;AAAA,MAEA;AAAA,KACF;AACF,IAAA;AAAA,EACF;AAEA,EAAA,CAAA,CAAE,OAAA,GAAU,IAAA;AACd;;;;"} | ||
| {"version":3,"file":"register.js","sources":["../../../../src/orchestrion/runtime/register.ts"],"sourcesContent":["import { debug } from '@sentry/core';\nimport { createRequire } from 'node:module';\nimport * as Module from 'node:module';\nimport { pathToFileURL } from 'node:url';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { SENTRY_INSTRUMENTATIONS } from '../config';\n\ndeclare global {\n // eslint-disable-next-line no-var\n var __SENTRY_ORCHESTRION__: { runtime?: boolean; bundler?: boolean } | undefined;\n}\n\n/**\n * Synchronously register the diagnostics-channel injection module hooks.\n *\n * This is the single source of truth for the registration logic. It is used by:\n * - `Sentry.init()` (the Node SDK calls it directly — that's why this module\n * must be CJS-compatible / dual-built, so it can be `require()`d synchronously\n * before the app's `import`s resolve), and\n * - `import-hook.mjs`, the side-effecting `--import` entry, which just calls it.\n *\n * Libraries imported *after* this call publish the `tracingChannel` events that\n * the channel-based integrations subscribe to.\n *\n * Idempotent via `globalThis.__SENTRY_ORCHESTRION__` — a no-op if the runtime\n * `--import` hook or a bundler plugin already injected the channels.\n */\nexport function registerDiagnosticsChannelInjection(): void {\n const g = (globalThis.__SENTRY_ORCHESTRION__ ??= {});\n\n // Already injected (runtime --import hook or bundler plugin) — nothing to do.\n if (g.runtime || g.bundler) {\n return;\n }\n\n const globalAny = globalThis as { Bun?: unknown; Deno?: { version?: { deno?: string } } };\n const parseVersion = (v: string): number[] => v.split('.').map(n => parseInt(n, 10));\n const nodeVersion = parseVersion(process.versions.node ?? '0.0.0');\n const denoVersion = parseVersion(globalAny.Deno?.version?.deno ?? '0.0.0');\n // `Module.registerHooks` only became stable in Node 24.13 / 25.1 and Deno 2.8.\n const stableSyncHooks =\n (nodeVersion[0] ?? 0) > 25 ||\n (nodeVersion[0] === 25 && (nodeVersion[1] ?? 0) >= 1) ||\n (nodeVersion[0] === 24 && (nodeVersion[1] ?? 0) >= 13) ||\n (denoVersion[0] ?? 0) > 2 ||\n (denoVersion[0] === 2 && (denoVersion[1] ?? 0) >= 8);\n\n let nodeRequire: (specifier: string) => unknown;\n /*! rollup-include-cjs-only */\n nodeRequire = require;\n /*! rollup-include-cjs-only-end */\n /*! rollup-include-esm-only */\n nodeRequire = createRequire(import.meta.url);\n /*! rollup-include-esm-only-end */\n\n // `Module.registerHooks` / `Module.register` are newer than the @types/node\n // we build against, hence the cast.\n const mod = Module as unknown as {\n registerHooks?: (hooks: unknown) => void;\n register?: (specifier: string, options: unknown) => void;\n };\n\n // runs both at `--import` time and (synchronously) inside `Sentry.init()`,\n // so an unguarded throw would either abort startup or make `init()` throw.\n // On any failure (e.g. dep resolution, `require(esm)` / Node-compat\n // incompatibility) we warn (DEBUG only) and continue without channel\n // injection\n try {\n if (typeof mod.registerHooks === 'function' && stableSyncHooks) {\n // Sync hooks cover CJS and ESM, no separate `_compile` patch needed.\n // We require() the module here so that we can synchronously load it,\n // including from a CommonJS Sentry build, without bundlers pulling in.\n // All versions in stableSyncHooks support this.\n const { initialize, resolve, load } = nodeRequire('@apm-js-collab/tracing-hooks/hook-sync.mjs') as {\n initialize: (opts: { instrumentations: unknown }) => void;\n resolve: unknown;\n load: unknown;\n };\n initialize({ instrumentations: SENTRY_INSTRUMENTATIONS });\n mod.registerHooks({ resolve, load });\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.registerHooks()');\n } else if (typeof mod.register === 'function' && !globalAny.Bun && !globalAny.Deno) {\n // `Module.register` + the `_compile` patch is Node 18.19–24.12 / 25.0\n // path. Bun/Deno are excluded: they don't support this combination and\n // must use the stable `registerHooks` path above (or none at all).\n let parentURL: string;\n /*! rollup-include-cjs-only */\n parentURL = pathToFileURL(__filename).href;\n /*! rollup-include-cjs-only-end */\n /*! rollup-include-esm-only */\n parentURL = import.meta.url;\n /*! rollup-include-esm-only-end */\n\n mod.register('@apm-js-collab/tracing-hooks/hook.mjs', {\n parentURL,\n data: { instrumentations: SENTRY_INSTRUMENTATIONS },\n });\n\n // ALSO patch `Module.prototype._compile` for the CJS side: when an ESM\n // file `import`s a CJS package, the package's internal `require()` calls\n // are resolved through the CJS machinery and never reach the ESM\n // register hook, so without this patch the file we want to instrument\n // loads untransformed.\n const ModulePatch = nodeRequire('@apm-js-collab/tracing-hooks') as new (opts: { instrumentations: unknown }) => {\n patch: () => void;\n };\n new ModulePatch({ instrumentations: SENTRY_INSTRUMENTATIONS }).patch();\n DEBUG_BUILD && debug.log('[orchestrion] registered diagnostics-channel injection via Module.register()');\n } else {\n DEBUG_BUILD &&\n debug.warn('[Sentry] No available Node API to register diagnostics-channel injection hooks; skipping.');\n return;\n }\n } catch (error) {\n DEBUG_BUILD &&\n debug.warn(\n '[Sentry] Failed to register diagnostics-channel injection hooks; channel-based integrations ' +\n 'will not record spans.',\n error,\n );\n return;\n }\n\n g.runtime = true;\n}\n"],"names":[],"mappings":";;;;;;;AA2BO,SAAS,mCAAA,GAA4C;AAC1D,EAAA,MAAM,CAAA,GAAK,UAAA,CAAW,sBAAA,KAAX,UAAA,CAAW,yBAA2B,EAAC,CAAA;AAGlD,EAAA,IAAI,CAAA,CAAE,OAAA,IAAW,CAAA,CAAE,OAAA,EAAS;AAC1B,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,UAAA;AAClB,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAwB,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,GAAA,CAAI,CAAA,CAAA,KAAK,QAAA,CAAS,CAAA,EAAG,EAAE,CAAC,CAAA;AACnF,EAAA,MAAM,WAAA,GAAc,YAAA,CAAa,OAAA,CAAQ,QAAA,CAAS,QAAQ,OAAO,CAAA;AACjE,EAAA,MAAM,cAAc,YAAA,CAAa,SAAA,CAAU,IAAA,EAAM,OAAA,EAAS,QAAQ,OAAO,CAAA;AAEzE,EAAA,MAAM,mBACH,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,MACvB,WAAA,CAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,YAAY,CAAC,CAAA,IAAK,CAAA,KAAM,CAAA,IAClD,YAAY,CAAC,CAAA,KAAM,EAAA,IAAA,CAAO,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,KAAM,EAAA,IAAA,CAClD,WAAA,CAAY,CAAC,CAAA,IAAK,CAAA,IAAK,CAAA,IACvB,WAAA,CAAY,CAAC,CAAA,KAAM,CAAA,IAAA,CAAM,WAAA,CAAY,CAAC,KAAK,CAAA,KAAM,CAAA;AAEpD,EAAA,IAAI,WAAA;AAAA,EACJ,WAAA,GAAA,aAAA,CAAA,MAAA,CAAA,IAAA,CAAA,GAAA,CAAA;AACA,EAAA,MAAA,GAAA,GAAA,MAAc;AAAA,EACd,IAAA;AAAA,IACA,IAAA,OAAA,GAAA,CAAA,aAAA,KAAA,UAAA,IAAA,eAAA,EAAA;AACA,MAAA,MAAA,EAAA,UAAc,EAAA,kBAA0B,WAAG,CAAA,4CAAA,CAAA;AAAA,MAC3C,UAAA,CAAA,EAAA,gBAAA,EAAA,uBAAA,EAAA,CAAA;AAIA,MAAA,GAAM,CAAA,aAAM,CAAA,EAAA,OAAA,EAAA,IAAA,EAAA,CAAA;AAUZ,MAAI,WAAA,IAAA,KAAA,CAAA,GAAA,CAAA,mFAAA,CAAA;AACF,IAAA,CAAA,MAAI,IAAO,OAAI,GAAA,CAAA,QAAA,KAAkB,UAAA,IAAc,CAAA,SAAA,CAAA,GAAA,IAAiB,CAAA,SAAA,CAAA,IAAA,EAAA;AAK9D,MAAA,IAAA,SAAQ;AAKR,MAAA,SAAA,GAAW,MAAE,CAAA,IAAA,CAAA,GAAA;AACb,MAAA,GAAA,CAAI,QAAA,CAAA,uCAA+B,EAAA;AACnC,QAAA,SAAA;AAA4G,QAC9G,IAAA,EAAA,EAAW,gBAAW,EAAA,uBAA4B;AAIhD,OAAA,CAAA;AAAI,MACJ,MAAA,WAAA,GAAA,WAAA,CAAA,8BAAA,CAAA;AACA,MAAA,IAAA,WAAY,CAAA,EAAA,kBAAwB,uBAAE,EAAA,CAAA,CAAA,KAAA,EAAA;AAAA,MACtC,WAAA,IAAA,KAAA,CAAA,GAAA,CAAA,8EAAA,CAAA;AAAA,IAAA,CAAA,MACA;AACA,MAAA,WAAA,IAAY,KAAA,CAAA,IAAY,CAAA,2FAAA,CAAA;AAAA,MACxB;AAEA,IAAA;AAAsD,EAAA,CAAA,CAAA,OACpD,KAAA,EAAA;AAAA,IAAA,WACM,IAAE,KAAA,CAAA,IAAA;AAA0C,MACpD,oHAAC;AAOD,MAAA;AAGA,KAAA;AACA,IAAA;AAAuG,EAAA;AAEvG,EAAA,CAAA,CAAA,OAAA,GAAA,IAAA;AAEA;;;;"} |
@@ -1,1 +0,1 @@ | ||
| {"type":"module","version":"10.63.0","sideEffects":false} | ||
| {"type":"module","version":"10.64.0","sideEffects":false} |
@@ -1,2 +0,2 @@ | ||
| import { getAsyncContextStrategy, getMainCarrier, debug, captureException, SPAN_STATUS_ERROR } from '@sentry/core'; | ||
| import { getAsyncContextStrategy, getMainCarrier, debug, SPAN_STATUS_ERROR, captureException } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from './debug-build.js'; | ||
@@ -120,3 +120,3 @@ import { ERROR_TYPE } from '@sentry/conventions/attributes'; | ||
| const raw = isObject ? "message" in error ? error.message : void 0 : error; | ||
| const message = raw ? String(raw) : "unknown_error"; | ||
| const message = raw ? String(raw) : void 0; | ||
| const type = isObject && "name" in error ? String(error.name) : "unknown"; | ||
@@ -123,0 +123,0 @@ return { |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"tracing-channel.js","sources":["../../src/tracing-channel.ts"],"sourcesContent":["import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\nimport type { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core';\nimport { debug, captureException, SPAN_STATUS_ERROR, getAsyncContextStrategy, getMainCarrier } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n /**\n * The current active span for the traced call.\n */\n _sentrySpan?: Span;\n\n /**\n * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing.\n */\n _sentryCallerStore?: unknown;\n};\n\n/*\n * A type patch so that we don't have to handle all subscription types.\n */\nexport interface SentryTracingChannel<TData extends object = object> extends Omit<\n TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>,\n 'subscribe' | 'unsubscribe'\n> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n}\n\nexport interface TracingChannelLifeCycleOptions<TData extends object = object> {\n /**\n * Invoked with the span and the channel context object once the traced operation completes\n * Use it to enrich the span from the result/error (branch on `'error' in data` / `'result' in data`) or to run cleanup.\n */\n beforeSpanEnd?: (span: Span, data: TracingChannelPayloadWithSpan<TData>) => void;\n\n /**\n * Whether a thrown error is captured as a Sentry event. The span is always marked with error status regardless. Defaults to `false`.\n * You can alternatively pass a function that sets the ExclusiveEventHintOrCaptureContext on the captured error.\n * Set `true` for instrumentations that own the error boundary, (e.g: route handlers)\n * For database drivers, it is not recommended to set this at all.\n */\n captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext);\n\n /**\n * Take ownership of *when* the span ends: return `true` and the helper won't end it on\n * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that\n * completes via its own `'end'`/`'error'` events.\n *\n * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span\n * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false`\n * lets the helper end the span as usual.\n */\n deferSpanEnd?: (args: {\n span: Span;\n data: TracingChannelPayloadWithSpan<TData>;\n /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */\n end: (error?: unknown) => void;\n }) => boolean;\n}\n\n/** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */\nexport interface TracingChannelBindingHandle<TData extends object = object> {\n /**\n * The tracing channel with the span bound into async context.\n */\n channel: SentryTracingChannel<TData>;\n\n /**\n * Tears down the binding: unsubscribes lifecycle handlers, when present, and unbinds the start store.\n * Idempotent, and a no-op when no async context binding was available.\n */\n unbind: () => void;\n}\n\nconst NOOP = (): void => {};\n\n/**\n * Bind a span and its lifecycle to a tracing channel so the span becomes the active async context\n * for the traced operation and is ended when the operation completes.\n *\n * `getSpan` may return `undefined` to opt a payload out entirely: nothing is bound, no span is\n * tracked, and the active context is left untouched. Use it for events that ride the same channel\n * but should reuse the enclosing span instead of opening (and ending) their own — e.g. an agent\n * loop's per-step events, where ending a freshly opened span would close the parent prematurely.\n */\nexport function bindTracingChannelToSpan<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n opts?: TracingChannelLifeCycleOptions<TData>,\n): TracingChannelBindingHandle<TData> {\n const handle = bindSpanToChannelStore(channel, getSpan);\n\n const beforeSpanEnd = opts?.beforeSpanEnd;\n const deferSpanEnd = opts?.deferSpanEnd;\n const getErrorHint = (e: unknown): ExclusiveEventHintOrCaptureContext => {\n if (typeof opts?.captureError === 'function') {\n return opts.captureError(e);\n }\n\n return {\n mechanism: {\n type: 'auto.diagnostic_channels.bind_span',\n handled: false,\n },\n };\n };\n\n // Apply Sentry error status + attributes (and capture, if configured) to a span. Shared by the\n // channel `error` lifecycle and the deferred `end` util so the two can't drift.\n const annotateSpanError = (span: Span, error: unknown): void => {\n if (opts?.captureError) {\n captureException(error, getErrorHint(error));\n }\n\n const { message, attributes } = getErrorInfo(error);\n span.setStatus({ code: SPAN_STATUS_ERROR, message });\n span.setAttributes(attributes);\n };\n\n // Creates an end fn for deferred handlers to use, ensures consistent span end behavior\n const makeDeferredEnd = (span: Span, data: TracingChannelPayloadWithSpan<TData>) => {\n let ended = false;\n\n return (error?: unknown): void => {\n if (ended) {\n return;\n }\n\n ended = true;\n if (error !== undefined) {\n annotateSpanError(span, error);\n }\n\n endBoundSpan(data, beforeSpanEnd);\n };\n };\n\n const subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>> = {\n start: NOOP,\n asyncStart: NOOP,\n end(data) {\n // The operation settled synchronously (returned or threw)\n // Presence checks because caller can return `undefined` result or throw a falsy value.\n if ('error' in data || 'result' in data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n }\n },\n error(data) {\n // No span was bound for this payload (`getSpan` returned undefined), so there is nothing to\n // annotate and no instrumentation that owns capturing this error.\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n\n annotateSpanError(span, data.error);\n },\n asyncEnd(data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n },\n };\n\n handle.channel.subscribe(subscribers);\n\n return {\n channel: handle.channel,\n unbind: () => {\n handle.channel.unsubscribe(subscribers);\n handle.unbind();\n },\n };\n}\n\n/**\n * Bind a span into the channel's async context so it becomes active for the traced operation,\n * without managing its lifecycle. The primitive behind {@link bindTracingChannelToSpan}, which\n * layers span-ending and error handling on top.\n *\n * `getSpan` may return `undefined` to leave the active context untouched for that payload.\n */\nfunction bindSpanToChannelStore<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n): TracingChannelBindingHandle<TData> {\n // Grabs the tracing channel binding defined by the AsyncContext strategy implementation\n const binding = getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.();\n\n // If no binding, then either the implementer doesn't support tracing channels or there is no active strategy\n // Failure mode here means we would still access the channel and potentially subscribe to it, but parenting will be off.\n if (!binding) {\n DEBUG_BUILD && debug.log('[TracingChannel] Could not access async context binding.');\n\n return {\n channel,\n unbind: NOOP,\n };\n }\n\n // Grab the ALS instance, we don't really care what is in it as long as the AsyncContext strategy can use its value to figure out parenting.\n const asyncLocalStorage = binding.asyncLocalStorage as AsyncLocalStorage<TData>;\n\n // bindStore activates the ALS for the traced call; any getStore() inside it returns the value bound for that context.\n // 1. Produce: getStoreWithActiveSpan(span) clones the current scope, plants the span via _INTERNAL_setSpanForScope, and returns { scope, isolationScope }, the active context carrying our span.\n // 2. Bind: the courier hands that opaque value to channel.start.bindStore(asyncLocalStorage, producer), which runs the traced op inside asyncLocalStorage.run(value, …); it never inspects the value.\n // 3. Read: inside the op, Sentry's scope machinery calls getScopes() → asyncStorage.getStore() on that same ALS, so getCurrentScope/getIsolationScope/getActiveSpan resolve to the scope carrying our span.\n // 4. Nest: any child span started in the traced op parents to that active span.\n channel.start.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n // Stash the caller's store before we swap in the span store, so `asyncStart` can restore it for\n // callback-style channels (see `_sentryCallerStore`).\n data._sentryCallerStore = asyncLocalStorage.getStore();\n\n const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return data._sentryCallerStore as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n // Restore the caller's context for the async continuation. Only callback-style channels `runStores`\n // `asyncStart` (so the callback runs inside this store). promise channels `publish` it, leaving this\n // inert, their continuation already inherits the caller's context natively.\n channel.asyncStart.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n return data._sentryCallerStore as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the stores\n channel.start.unbindStore(asyncLocalStorage);\n channel.asyncStart.unbindStore(asyncLocalStorage);\n },\n };\n}\n\nfunction endBoundSpan<TData extends object>(\n data: TracingChannelPayloadWithSpan<TData>,\n beforeSpanEnd: TracingChannelLifeCycleOptions<TData>['beforeSpanEnd'],\n): void {\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n beforeSpanEnd?.(span, data);\n span.end();\n}\n\ntype ErrorInfo = {\n message: string;\n attributes: Record<string, string>;\n};\n\n/**\n * Best-effort message and attribute extraction for thrown/rejected values.\n */\nfunction getErrorInfo(error: unknown): ErrorInfo {\n const isObject = !!error && typeof error === 'object';\n const raw = isObject ? ('message' in error ? error.message : undefined) : error;\n\n const message = raw ? String(raw) : 'unknown_error';\n const type = isObject && 'name' in error ? String(error.name) : 'unknown';\n\n return {\n message,\n attributes: {\n [ERROR_TYPE]: type,\n },\n };\n}\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"tracing-channel.js","sources":["../../src/tracing-channel.ts"],"sourcesContent":["import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel';\nimport type { AsyncLocalStorage } from 'node:async_hooks';\nimport type { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core';\nimport { debug, captureException, SPAN_STATUS_ERROR, getAsyncContextStrategy, getMainCarrier } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\nimport { ERROR_TYPE } from '@sentry/conventions/attributes';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n /**\n * The current active span for the traced call.\n */\n _sentrySpan?: Span;\n\n /**\n * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing.\n */\n _sentryCallerStore?: unknown;\n};\n\n/*\n * A type patch so that we don't have to handle all subscription types.\n */\nexport interface SentryTracingChannel<TData extends object = object> extends Omit<\n TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>,\n 'subscribe' | 'unsubscribe'\n> {\n subscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n unsubscribe(subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>>): void;\n}\n\nexport interface TracingChannelLifeCycleOptions<TData extends object = object> {\n /**\n * Invoked with the span and the channel context object once the traced operation completes\n * Use it to enrich the span from the result/error (branch on `'error' in data` / `'result' in data`) or to run cleanup.\n */\n beforeSpanEnd?: (span: Span, data: TracingChannelPayloadWithSpan<TData>) => void;\n\n /**\n * Whether a thrown error is captured as a Sentry event. The span is always marked with error status regardless. Defaults to `false`.\n * You can alternatively pass a function that sets the ExclusiveEventHintOrCaptureContext on the captured error.\n * Set `true` for instrumentations that own the error boundary, (e.g: route handlers)\n * For database drivers, it is not recommended to set this at all.\n */\n captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext);\n\n /**\n * Take ownership of *when* the span ends: return `true` and the helper won't end it on\n * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that\n * completes via its own `'end'`/`'error'` events.\n *\n * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span\n * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false`\n * lets the helper end the span as usual.\n */\n deferSpanEnd?: (args: {\n span: Span;\n data: TracingChannelPayloadWithSpan<TData>;\n /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */\n end: (error?: unknown) => void;\n }) => boolean;\n}\n\n/** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */\nexport interface TracingChannelBindingHandle<TData extends object = object> {\n /**\n * The tracing channel with the span bound into async context.\n */\n channel: SentryTracingChannel<TData>;\n\n /**\n * Tears down the binding: unsubscribes lifecycle handlers, when present, and unbinds the start store.\n * Idempotent, and a no-op when no async context binding was available.\n */\n unbind: () => void;\n}\n\nconst NOOP = (): void => {};\n\n/**\n * Bind a span and its lifecycle to a tracing channel so the span becomes the active async context\n * for the traced operation and is ended when the operation completes.\n *\n * `getSpan` may return `undefined` to opt a payload out entirely: nothing is bound, no span is\n * tracked, and the active context is left untouched. Use it for events that ride the same channel\n * but should reuse the enclosing span instead of opening (and ending) their own — e.g. an agent\n * loop's per-step events, where ending a freshly opened span would close the parent prematurely.\n */\nexport function bindTracingChannelToSpan<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n opts?: TracingChannelLifeCycleOptions<TData>,\n): TracingChannelBindingHandle<TData> {\n const handle = bindSpanToChannelStore(channel, getSpan);\n\n const beforeSpanEnd = opts?.beforeSpanEnd;\n const deferSpanEnd = opts?.deferSpanEnd;\n const getErrorHint = (e: unknown): ExclusiveEventHintOrCaptureContext => {\n if (typeof opts?.captureError === 'function') {\n return opts.captureError(e);\n }\n\n return {\n mechanism: {\n type: 'auto.diagnostic_channels.bind_span',\n handled: false,\n },\n };\n };\n\n // Apply Sentry error status + attributes (and capture, if configured) to a span. Shared by the\n // channel `error` lifecycle and the deferred `end` util so the two can't drift.\n const annotateSpanError = (span: Span, error: unknown): void => {\n if (opts?.captureError) {\n captureException(error, getErrorHint(error));\n }\n\n const { message, attributes } = getErrorInfo(error);\n span.setStatus({ code: SPAN_STATUS_ERROR, message });\n span.setAttributes(attributes);\n };\n\n // Creates an end fn for deferred handlers to use, ensures consistent span end behavior\n const makeDeferredEnd = (span: Span, data: TracingChannelPayloadWithSpan<TData>) => {\n let ended = false;\n\n return (error?: unknown): void => {\n if (ended) {\n return;\n }\n\n ended = true;\n if (error !== undefined) {\n annotateSpanError(span, error);\n }\n\n endBoundSpan(data, beforeSpanEnd);\n };\n };\n\n const subscribers: Partial<TracingChannelSubscribers<TracingChannelPayloadWithSpan<TData>>> = {\n start: NOOP,\n asyncStart: NOOP,\n end(data) {\n // The operation settled synchronously (returned or threw)\n // Presence checks because caller can return `undefined` result or throw a falsy value.\n if ('error' in data || 'result' in data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n }\n },\n error(data) {\n // No span was bound for this payload (`getSpan` returned undefined), so there is nothing to\n // annotate and no instrumentation that owns capturing this error.\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n\n annotateSpanError(span, data.error);\n },\n asyncEnd(data) {\n const span = data._sentrySpan;\n if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) {\n return;\n }\n endBoundSpan(data, beforeSpanEnd);\n },\n };\n\n handle.channel.subscribe(subscribers);\n\n return {\n channel: handle.channel,\n unbind: () => {\n handle.channel.unsubscribe(subscribers);\n handle.unbind();\n },\n };\n}\n\n/**\n * Bind a span into the channel's async context so it becomes active for the traced operation,\n * without managing its lifecycle. The primitive behind {@link bindTracingChannelToSpan}, which\n * layers span-ending and error handling on top.\n *\n * `getSpan` may return `undefined` to leave the active context untouched for that payload.\n */\nfunction bindSpanToChannelStore<TData extends object>(\n channel: TracingChannel<TData, TData>,\n getSpan: (data: TracingChannelPayloadWithSpan<TData>) => Span | undefined,\n): TracingChannelBindingHandle<TData> {\n // Grabs the tracing channel binding defined by the AsyncContext strategy implementation\n const binding = getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.();\n\n // If no binding, then either the implementer doesn't support tracing channels or there is no active strategy\n // Failure mode here means we would still access the channel and potentially subscribe to it, but parenting will be off.\n if (!binding) {\n DEBUG_BUILD && debug.log('[TracingChannel] Could not access async context binding.');\n\n return {\n channel,\n unbind: NOOP,\n };\n }\n\n // Grab the ALS instance, we don't really care what is in it as long as the AsyncContext strategy can use its value to figure out parenting.\n const asyncLocalStorage = binding.asyncLocalStorage as AsyncLocalStorage<TData>;\n\n // bindStore activates the ALS for the traced call; any getStore() inside it returns the value bound for that context.\n // 1. Produce: getStoreWithActiveSpan(span) clones the current scope, plants the span via _INTERNAL_setSpanForScope, and returns { scope, isolationScope }, the active context carrying our span.\n // 2. Bind: the courier hands that opaque value to channel.start.bindStore(asyncLocalStorage, producer), which runs the traced op inside asyncLocalStorage.run(value, …); it never inspects the value.\n // 3. Read: inside the op, Sentry's scope machinery calls getScopes() → asyncStorage.getStore() on that same ALS, so getCurrentScope/getIsolationScope/getActiveSpan resolve to the scope carrying our span.\n // 4. Nest: any child span started in the traced op parents to that active span.\n channel.start.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n // Stash the caller's store before we swap in the span store, so `asyncStart` can restore it for\n // callback-style channels (see `_sentryCallerStore`).\n data._sentryCallerStore = asyncLocalStorage.getStore();\n\n const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return data._sentryCallerStore as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n // Restore the caller's context for the async continuation. Only callback-style channels `runStores`\n // `asyncStart` (so the callback runs inside this store). promise channels `publish` it, leaving this\n // inert, their continuation already inherits the caller's context natively.\n channel.asyncStart.bindStore(asyncLocalStorage, (data: TracingChannelPayloadWithSpan<TData>) => {\n return data._sentryCallerStore as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the stores\n channel.start.unbindStore(asyncLocalStorage);\n channel.asyncStart.unbindStore(asyncLocalStorage);\n },\n };\n}\n\nfunction endBoundSpan<TData extends object>(\n data: TracingChannelPayloadWithSpan<TData>,\n beforeSpanEnd: TracingChannelLifeCycleOptions<TData>['beforeSpanEnd'],\n): void {\n const span = data._sentrySpan;\n if (!span) {\n return;\n }\n beforeSpanEnd?.(span, data);\n span.end();\n}\n\ntype ErrorInfo = {\n message: string | undefined;\n attributes: Record<string, string>;\n};\n\n/**\n * Best-effort message and attribute extraction for thrown/rejected values.\n */\nfunction getErrorInfo(error: unknown): ErrorInfo {\n const isObject = !!error && typeof error === 'object';\n const raw = isObject ? ('message' in error ? error.message : undefined) : error;\n\n // Leave the status message unset if not set (e.g. an `AggregateError` from\n // ECONNREFUSED, whose `.message` is empty). Otherwise cast to string.\n const message = raw ? String(raw) : undefined;\n const type = isObject && 'name' in error ? String(error.name) : 'unknown';\n\n return {\n message,\n attributes: {\n [ERROR_TYPE]: type,\n },\n };\n}\n"],"names":[],"mappings":";;;;AA4EA,MAAM,OAAO,MAAY;AAAC,CAAA;AAWnB,SAAS,wBAAA,CACd,OAAA,EACA,OAAA,EACA,IAAA,EACoC;AACpC,EAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,OAAA,EAAS,OAAO,CAAA;AAEtD,EAAA,MAAM,gBAAgB,IAAA,EAAM,aAAA;AAC5B,EAAA,MAAM,eAAe,IAAA,EAAM,YAAA;AAC3B,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAmD;AACvE,IAAA,IAAI,OAAO,IAAA,EAAM,YAAA,KAAiB,UAAA,EAAY;AAC5C,MAAA,OAAO,IAAA,CAAK,aAAa,CAAC,CAAA;AAAA,IAC5B;AAEA,IAAA,OAAO;AAAA,MACL,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,oCAAA;AAAA,QACN,OAAA,EAAS;AAAA;AACX,KACF;AAAA,EACF,CAAA;AAIA,EAAA,MAAM,iBAAA,GAAoB,CAAC,IAAA,EAAY,KAAA,KAAyB;AAC9D,IAAA,IAAI,MAAM,YAAA,EAAc;AACtB,MAAA,gBAAA,CAAiB,KAAA,EAAO,YAAA,CAAa,KAAK,CAAC,CAAA;AAAA,IAC7C;AAEA,IAAA,MAAM,EAAE,OAAA,EAAS,UAAA,EAAW,GAAI,aAAa,KAAK,CAAA;AAClD,IAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,iBAAA,EAAmB,SAAS,CAAA;AACnD,IAAA,IAAA,CAAK,cAAc,UAAU,CAAA;AAAA,EAC/B,CAAA;AAGA,EAAA,MAAM,eAAA,GAAkB,CAAC,IAAA,EAAY,IAAA,KAA+C;AAClF,IAAA,IAAI,KAAA,GAAQ,KAAA;AAEZ,IAAA,OAAO,CAAC,KAAA,KAA0B;AAChC,MAAA,IAAI,KAAA,EAAO;AACT,QAAA;AAAA,MACF;AAEA,MAAA,KAAA,GAAQ,IAAA;AACR,MAAA,IAAI,UAAU,MAAA,EAAW;AACvB,QAAA,iBAAA,CAAkB,MAAM,KAAK,CAAA;AAAA,MAC/B;AAEA,MAAA,YAAA,CAAa,MAAM,aAAa,CAAA;AAAA,IAClC,CAAA;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAwF;AAAA,IAC5F,KAAA,EAAO,IAAA;AAAA,IACP,UAAA,EAAY,IAAA;AAAA,IACZ,IAAI,IAAA,EAAM;AAGR,MAAA,IAAI,OAAA,IAAW,IAAA,IAAQ,QAAA,IAAY,IAAA,EAAM;AACvC,QAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,QAAA,IAAI,IAAA,IAAQ,YAAA,GAAe,EAAE,IAAA,EAAM,IAAA,EAAM,GAAA,EAAK,eAAA,CAAgB,IAAA,EAAM,IAAI,CAAA,EAAG,CAAA,EAAG;AAC5E,UAAA;AAAA,QACF;AACA,QAAA,YAAA,CAAa,MAAM,aAAa,CAAA;AAAA,MAClC;AAAA,IACF,CAAA;AAAA,IACA,MAAM,IAAA,EAAM;AAGV,MAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA;AAAA,MACF;AAEA,MAAA,iBAAA,CAAkB,IAAA,EAAM,KAAK,KAAK,CAAA;AAAA,IACpC,CAAA;AAAA,IACA,SAAS,IAAA,EAAM;AACb,MAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,MAAA,IAAI,IAAA,IAAQ,YAAA,GAAe,EAAE,IAAA,EAAM,IAAA,EAAM,GAAA,EAAK,eAAA,CAAgB,IAAA,EAAM,IAAI,CAAA,EAAG,CAAA,EAAG;AAC5E,QAAA;AAAA,MACF;AACA,MAAA,YAAA,CAAa,MAAM,aAAa,CAAA;AAAA,IAClC;AAAA,GACF;AAEA,EAAA,MAAA,CAAO,OAAA,CAAQ,UAAU,WAAW,CAAA;AAEpC,EAAA,OAAO;AAAA,IACL,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,QAAQ,MAAM;AACZ,MAAA,MAAA,CAAO,OAAA,CAAQ,YAAY,WAAW,CAAA;AACtC,MAAA,MAAA,CAAO,MAAA,EAAO;AAAA,IAChB;AAAA,GACF;AACF;AASA,SAAS,sBAAA,CACP,SACA,OAAA,EACoC;AAEpC,EAAA,MAAM,OAAA,GAAU,uBAAA,CAAwB,cAAA,EAAgB,EAAE,wBAAA,IAA2B;AAIrF,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,WAAA,IAAe,KAAA,CAAM,IAAI,0DAA0D,CAAA;AAEnF,IAAA,OAAO;AAAA,MACL,OAAA;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,oBAAoB,OAAA,CAAQ,iBAAA;AAOlC,EAAA,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,iBAAA,EAAmB,CAAC,IAAA,KAA+C;AAGzF,IAAA,IAAA,CAAK,kBAAA,GAAqB,kBAAkB,QAAA,EAAS;AAErD,IAAA,MAAM,IAAA,GAAO,QAAQ,IAAI,CAAA;AACzB,IAAA,IAAI,CAAC,IAAA,EAAM;AAET,MAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,IACd;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAEnB,IAAA,OAAO,OAAA,CAAQ,uBAAuB,IAAI,CAAA;AAAA,EAC5C,CAAC,CAAA;AAKD,EAAA,OAAA,CAAQ,UAAA,CAAW,SAAA,CAAU,iBAAA,EAAmB,CAAC,IAAA,KAA+C;AAC9F,IAAA,OAAO,IAAA,CAAK,kBAAA;AAAA,EACd,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,QAAQ,MAAM;AAEZ,MAAA,OAAA,CAAQ,KAAA,CAAM,YAAY,iBAAiB,CAAA;AAC3C,MAAA,OAAA,CAAQ,UAAA,CAAW,YAAY,iBAAiB,CAAA;AAAA,IAClD;AAAA,GACF;AACF;AAEA,SAAS,YAAA,CACP,MACA,aAAA,EACM;AACN,EAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA;AAAA,EACF;AACA,EAAA,aAAA,GAAgB,MAAM,IAAI,CAAA;AAC1B,EAAA,IAAA,CAAK,GAAA,EAAI;AACX;AAUA,SAAS,aAAa,KAAA,EAA2B;AAC/C,EAAA,MAAM,QAAA,GAAW,CAAC,CAAC,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA;AAC7C,EAAA,MAAM,MAAM,QAAA,GAAY,SAAA,IAAa,KAAA,GAAQ,KAAA,CAAM,UAAU,MAAA,GAAa,KAAA;AAI1E,EAAA,MAAM,OAAA,GAAU,GAAA,GAAM,MAAA,CAAO,GAAG,CAAA,GAAI,MAAA;AACpC,EAAA,MAAM,OAAO,QAAA,IAAY,MAAA,IAAU,QAAQ,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,GAAI,SAAA;AAEhE,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,UAAA,EAAY;AAAA,MACV,CAAC,UAAU,GAAG;AAAA;AAChB,GACF;AACF;;;;"} |
@@ -1,4 +0,4 @@ | ||
| import { GEN_AI_EMBEDDINGS_INPUT, GEN_AI_OPERATION_NAME, GEN_AI_FUNCTION_ID, GEN_AI_RESPONSE_STREAMING, GEN_AI_REQUEST_AVAILABLE_TOOLS, GEN_AI_TOOL_INPUT, GEN_AI_TOOL_NAME, GEN_AI_TOOL_TYPE, GEN_AI_TOOL_OUTPUT, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_RESPONSE_ID, GEN_AI_RESPONSE_MODEL, GEN_AI_OUTPUT_MESSAGES, GEN_AI_INPUT_MESSAGES, GEN_AI_REQUEST_MODEL, GEN_AI_SYSTEM } from '@sentry/conventions/attributes'; | ||
| import { GEN_AI_INVOKE_AGENT_SPAN_OP, GEN_AI_EXECUTE_TOOL_SPAN_OP } from '@sentry/conventions/op'; | ||
| import { startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getProviderMetadataAttributes, GEN_AI_CONVERSATION_ID_ATTRIBUTE, spanToJSON, SPAN_STATUS_ERROR, withScope, spanToTraceContext, captureException, getClient, shouldEnableTruncation, getTruncatedJsonString, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '@sentry/core'; | ||
| import { GEN_AI_EMBEDDINGS_INPUT, GEN_AI_OPERATION_NAME, GEN_AI_TOOL_INPUT, GEN_AI_TOOL_NAME, GEN_AI_TOOL_TYPE, GEN_AI_REQUEST_AVAILABLE_TOOLS, GEN_AI_FUNCTION_ID, GEN_AI_RESPONSE_STREAMING, GEN_AI_TOOL_OUTPUT, GEN_AI_USAGE_INPUT_TOKENS, GEN_AI_USAGE_OUTPUT_TOKENS, GEN_AI_USAGE_TOTAL_TOKENS, GEN_AI_RESPONSE_FINISH_REASONS, GEN_AI_RESPONSE_ID, GEN_AI_RESPONSE_MODEL, GEN_AI_OUTPUT_MESSAGES, GEN_AI_INPUT_MESSAGES, GEN_AI_REQUEST_MODEL, GEN_AI_SYSTEM } from '@sentry/conventions/attributes'; | ||
| import { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op'; | ||
| import { getClient, shouldEnableTruncation, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getTruncatedJsonString, getProviderMetadataAttributes, GEN_AI_CONVERSATION_ID_ATTRIBUTE, spanToJSON, SPAN_STATUS_ERROR, withScope, spanToTraceContext, captureException, GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE, GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE } from '@sentry/core'; | ||
| import { bindTracingChannelToSpan } from '../tracing-channel.js'; | ||
@@ -18,3 +18,3 @@ | ||
| const toolDescriptionsByCallId = /* @__PURE__ */ new Map(); | ||
| const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "rerank"]); | ||
| const ROOT_OPERATION_TYPES = /* @__PURE__ */ new Set(["generateText", "streamText", "embed", "embedMany", "rerank"]); | ||
| function clearOperationId(data) { | ||
@@ -26,6 +26,9 @@ if (!ROOT_OPERATION_TYPES.has(data.type)) { | ||
| if (callId) { | ||
| operationIdByCallId.delete(callId); | ||
| toolDescriptionsByCallId.delete(callId); | ||
| clearOperationCallId(callId); | ||
| } | ||
| } | ||
| function clearOperationCallId(callId) { | ||
| operationIdByCallId.delete(callId); | ||
| toolDescriptionsByCallId.delete(callId); | ||
| } | ||
| function recordToolDescriptions(callId, tools) { | ||
@@ -110,6 +113,9 @@ if (!callId || !Array.isArray(tools)) { | ||
| case "embed": | ||
| case "embedMany": { | ||
| const input = type === "embedMany" ? event.values : event.value; | ||
| return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, { | ||
| ...baseAttributes, | ||
| ...recordInputs && event.value !== void 0 ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {} | ||
| ...recordInputs && input !== void 0 ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(input) } : {} | ||
| }); | ||
| } | ||
| case "rerank": | ||
@@ -359,3 +365,3 @@ return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes); | ||
| export { clearOperationId, createSpanFromMessage, enrichSpanOnEnd, subscribeVercelAiTracingChannel }; | ||
| export { clearOperationCallId, clearOperationId, createSpanFromMessage, enrichSpanOnEnd, subscribeVercelAiTracingChannel }; | ||
| //# sourceMappingURL=vercel-ai-dc-subscriber.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n }\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\ntype VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\ninterface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && event.value !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(event.value) } : {}),\n });\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":[],"mappings":"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"} | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.js","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"sourcesContent":["/* eslint-disable max-lines */\n// `@sentry/conventions` marks several gen_ai attributes (e.g. `GEN_AI_SYSTEM`, `GEN_AI_TOOL_*`,\n// `GEN_AI_REQUEST_AVAILABLE_TOOLS`) as deprecated in favour of newer semconv names. We intentionally\n// keep emitting the current names so these spans match the OTel-based (v6) integration and what the\n// Sentry product consumes today; migrating to the new names is a separate, coordinated change.\n/* eslint-disable typescript-eslint/no-deprecated */\nimport {\n GEN_AI_EMBEDDINGS_INPUT,\n GEN_AI_FUNCTION_ID,\n GEN_AI_INPUT_MESSAGES,\n GEN_AI_OPERATION_NAME,\n GEN_AI_OUTPUT_MESSAGES,\n GEN_AI_REQUEST_AVAILABLE_TOOLS,\n GEN_AI_REQUEST_MODEL,\n GEN_AI_RESPONSE_FINISH_REASONS,\n GEN_AI_RESPONSE_ID,\n GEN_AI_RESPONSE_MODEL,\n GEN_AI_RESPONSE_STREAMING,\n GEN_AI_SYSTEM,\n GEN_AI_TOOL_INPUT,\n GEN_AI_TOOL_NAME,\n GEN_AI_TOOL_OUTPUT,\n GEN_AI_TOOL_TYPE,\n GEN_AI_USAGE_INPUT_TOKENS,\n GEN_AI_USAGE_OUTPUT_TOKENS,\n GEN_AI_USAGE_TOTAL_TOKENS,\n} from '@sentry/conventions/attributes';\nimport { GEN_AI_EXECUTE_TOOL_SPAN_OP, GEN_AI_INVOKE_AGENT_SPAN_OP } from '@sentry/conventions/op';\nimport type { Span } from '@sentry/core';\nimport {\n captureException,\n GEN_AI_CONVERSATION_ID_ATTRIBUTE,\n GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE,\n GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE,\n getClient,\n getProviderMetadataAttributes,\n getTruncatedJsonString,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n shouldEnableTruncation,\n SPAN_STATUS_ERROR,\n spanToJSON,\n spanToTraceContext,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport type { TracingChannel } from 'node:diagnostics_channel';\nimport { bindTracingChannelToSpan } from '../tracing-channel';\n\n/**\n * The single tracing channel the `ai` package (>= 7) publishes all telemetry lifecycle events to\n * via `node:diagnostics_channel`. Events are discriminated by their `type` field.\n * @see https://github.com/vercel/ai/pull/15660\n */\nconst AI_SDK_TELEMETRY_TRACING_CHANNEL = 'ai:telemetry';\n\nconst ORIGIN = 'auto.vercelai.channel';\n\n// `@sentry/conventions` does not expose these yet, so we keep the literals here.\nconst GEN_AI_TOOL_CALL_ID_ATTRIBUTE = 'gen_ai.tool.call.id';\nconst GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE = 'gen_ai.tool.description';\nconst GEN_AI_EMBEDDINGS_OPERATION = 'embeddings';\nconst GEN_AI_RERANK_OPERATION = 'rerank';\n// The model-call op matches the Vercel AI OTel integration (`gen_ai.generate_content`) rather than\n// the generic `gen_ai.chat`, so v6 (OTel) and v7 (channel) produce the same spans.\nconst GEN_AI_GENERATE_CONTENT_OPERATION = 'generate_content';\n\n// Subset of the `vercel.ai.*` passthrough attributes the OTel integration emits that we reproduce.\nconst VERCEL_AI_OPERATION_ID_ATTRIBUTE = 'vercel.ai.operationId';\nconst VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE = 'vercel.ai.model.provider';\nconst VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE = 'vercel.ai.settings.maxRetries';\n\n// Tracks the top-level operationId (and whether it streams) per `callId` so a model-call span can\n// name its `doGenerate`/`doStream` operation the same way the OTel integration does. `isStream` is\n// the authoritative event-type signal rather than a substring check on the (possibly custom)\n// operationId. Cleared when the top-level span ends.\nconst operationIdByCallId = new Map<string, { operationId: string; isStream: boolean }>();\n\n// Per-operation map of tool name → description, harvested from a model-call /\n// top-level event's `tools` (keyed by the shared `callId`). The AI SDK's\n// `executeTool` event doesn't carry the tool's description, so we backfill it\n// onto the tool span here — without relying on the OTel `vercelAiEventProcessor`\n// (which isn't registered in channel/orchestrion mode). Cleared with the\n// operation. Only populated when inputs are recorded, matching the OTel path\n// (which sources descriptions from the recorded `available_tools`).\nconst toolDescriptionsByCallId = new Map<string, Map<string, string>>();\n\n// Only top-level operations own the `callId` → operationId mapping; `step`/`languageModelCall`/\n// `executeTool` share the parent's `callId`, so they must not clear it.\nconst ROOT_OPERATION_TYPES = new Set<ChannelEventType>(['generateText', 'streamText', 'embed', 'embedMany', 'rerank']);\n\n/** Drop the per-operation `callId` maps once the owning top-level operation settles (success or error). */\nexport function clearOperationId(data: VercelAiChannelMessage): void {\n if (!ROOT_OPERATION_TYPES.has(data.type)) {\n return;\n }\n const callId = asString(data.event.callId);\n if (callId) {\n clearOperationCallId(callId);\n }\n}\n\n/**\n * Drop the per-operation `callId` maps for a single id. The v6 orchestrion adapter uses this to clear a\n * `streamText` operation only after its lazily-run model call settles — the operation's own span ends\n * synchronously (when `streamText` returns) but the model call runs later as the stream is consumed, and\n * it still needs the operation's `operationId`/`isStream` entry to name itself `ai.streamText.doStream`.\n */\nexport function clearOperationCallId(callId: string): void {\n operationIdByCallId.delete(callId);\n toolDescriptionsByCallId.delete(callId);\n}\n\n/** Record tool name → description from an event's `tools`, so tool spans can backfill the description. */\nfunction recordToolDescriptions(callId: string | undefined, tools: unknown): void {\n if (!callId || !Array.isArray(tools)) {\n return;\n }\n let descriptions = toolDescriptionsByCallId.get(callId);\n for (const tool of tools) {\n if (isRecord(tool) && typeof tool.name === 'string' && typeof tool.description === 'string') {\n descriptions = descriptions ?? new Map();\n if (!descriptions.has(tool.name)) {\n descriptions.set(tool.name, tool.description);\n }\n }\n }\n if (descriptions) {\n toolDescriptionsByCallId.set(callId, descriptions);\n }\n}\n\n/**\n * Resolve a tool's description, preferring the per-operation map (populated from the model-call /\n * top-level event's `tools`, v7) and falling back to a `tools` collection on the event itself —\n * which may be an array of `{ name, description }` or a record keyed by tool name (v6).\n */\nfunction resolveToolDescription(callId: string | undefined, toolName: string, tools: unknown): string | undefined {\n const fromMap = callId ? toolDescriptionsByCallId.get(callId)?.get(toolName) : undefined;\n if (fromMap) {\n return fromMap;\n }\n if (Array.isArray(tools)) {\n const match = tools.find(tool => isRecord(tool) && tool.name === toolName);\n return isRecord(match) ? asString(match.description) : undefined;\n }\n if (isRecord(tools)) {\n const tool = tools[toolName];\n return isRecord(tool) ? asString(tool.description) : undefined;\n }\n return undefined;\n}\n\n/** The lifecycle event types the `ai:telemetry` channel can carry. */\nexport type ChannelEventType =\n | 'generateText'\n | 'streamText'\n | 'step'\n | 'languageModelCall'\n | 'executeTool'\n | 'embed'\n | 'embedMany'\n | 'rerank';\n\n/**\n * The context object the AI SDK passes through one tracing-channel call. It is the same object\n * identity across `start`/`end`/`asyncEnd`/`error`, and Node's `tracingChannel` attaches\n * `result`/`error` to it as the traced promise settles.\n */\nexport interface VercelAiChannelMessage {\n type: ChannelEventType;\n event: Record<string, unknown>;\n result?: unknown;\n error?: unknown;\n}\n\n/**\n * Platform-provided factory that returns a tracing channel for the given channel name. The factory\n * is responsible for, when `start` fires, calling `transformStart(data)` and storing the returned\n * span on `data._sentrySpan` so the subscriber's `asyncEnd`/`error` handlers can read it.\n *\n * Node passes `@sentry/opentelemetry/tracing-channel`, which uses `bindStore` to additionally make\n * the span the active OTel context for the duration of the traced operation. That is what makes\n * nested AI SDK operations (model calls, tool calls) become children of the enclosing span without\n * any manual parent bookkeeping here.\n */\nexport type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>;\n\n/** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */\nexport interface VercelAiChannelOptions {\n recordInputs?: boolean;\n recordOutputs?: boolean;\n enableTruncation?: boolean;\n}\n\nlet subscribed = false;\n\n/**\n * Subscribe Sentry span handlers to the `ai` SDK's native telemetry tracing channel (`ai:telemetry`,\n * available in `ai` >= 7) and emit fully-formed `gen_ai.*` spans directly — no OpenTelemetry span\n * post-processing involved.\n *\n * The integration passes its options in directly (rather than us looking the integration up on every\n * event); the global `dataCollection.genAI` default is still read from the client per event.\n *\n * Safe to always call: on `ai` versions that don't publish to the channel (e.g. < 7) nothing is\n * ever emitted and this is inert, so there is no double-instrumentation against the OTel-based\n * patcher. Idempotent.\n */\nexport function subscribeVercelAiTracingChannel(\n tracingChannel: VercelAiTracingChannelFactory,\n options: VercelAiChannelOptions = {},\n): void {\n if (subscribed) {\n return;\n }\n subscribed = true;\n\n bindTracingChannelToSpan(\n tracingChannel<VercelAiChannelMessage>(AI_SDK_TELEMETRY_TRACING_CHANNEL),\n data => createSpanFromMessage(data, options),\n {\n // The helper ends the span; we enrich it from the settled result first (tokens, output messages,\n // finish reasons, response model/id, provider metadata) and drop the per-operation `callId` maps.\n beforeSpanEnd: (span, data) => {\n enrichSpanOnEnd(span, data, options);\n clearOperationId(data);\n },\n },\n );\n}\n\n/**\n * Transform a channel `start` payload into the span that should be active for the operation. For\n * `step` we deliberately don't open a span (model calls and tool calls are siblings under the\n * invoke_agent span, matching the OTel-based output), so we reuse the active span and mark the\n * payload to skip ending it.\n */\nexport function createSpanFromMessage(\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): Span | undefined {\n const { type, event } = data;\n\n if (type === 'step' || !event || typeof event !== 'object') {\n // Opt out: returning `undefined` leaves the enclosing `invoke_agent` span as the active context\n // (model-call and tool-call events nest under it) without opening — or ending — a span of its own.\n return undefined;\n }\n\n const { recordInputs, enableTruncation } = getRecordingOptions(event, channelOptions);\n const provider = asString(event.provider);\n const modelId = asString(event.modelId);\n const callId = asString(event.callId);\n const maxRetries = asNumber(event.maxRetries);\n\n // Harvest tool descriptions from the operation/model-call `tools` so tool spans can backfill them.\n // Gated on `recordInputs` to match the OTel path, which only records `available_tools` then.\n if (recordInputs) {\n recordToolDescriptions(callId, event.tools);\n }\n\n const baseAttributes: Record<string, string | number | boolean> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n ...(provider ? { [GEN_AI_SYSTEM]: provider, [VERCEL_AI_MODEL_PROVIDER_ATTRIBUTE]: provider } : {}),\n ...(modelId ? { [GEN_AI_REQUEST_MODEL]: modelId } : {}),\n ...(maxRetries !== undefined ? { [VERCEL_AI_SETTINGS_MAX_RETRIES_ATTRIBUTE]: maxRetries } : {}),\n };\n\n switch (type) {\n case 'generateText':\n case 'streamText':\n return buildInvokeAgentSpan(event, baseAttributes, recordInputs, enableTruncation, callId, type === 'streamText');\n case 'languageModelCall':\n return buildModelCallSpan(event, baseAttributes, recordInputs, enableTruncation, callId, modelId);\n case 'executeTool':\n return buildToolSpan(event, recordInputs);\n case 'embed':\n case 'embedMany': {\n // `embed` carries a single `value`; `embedMany` a `values` array — both map to the embeddings input.\n const input = type === 'embedMany' ? event.values : event.value;\n return startGenAiSpan(GEN_AI_EMBEDDINGS_OPERATION, modelId, {\n ...baseAttributes,\n ...(recordInputs && input !== undefined ? { [GEN_AI_EMBEDDINGS_INPUT]: safeStringify(input) } : {}),\n });\n }\n case 'rerank':\n return startGenAiSpan(GEN_AI_RERANK_OPERATION, modelId, baseAttributes);\n default:\n // Unknown event type: opt out rather than open a span we can't shape correctly.\n return undefined;\n }\n}\n\ntype Attributes = Record<string, string | number | boolean>;\n\n/** Start a `gen_ai.<operation>` span named `<operation> <suffix>` (or just `<operation>` when no suffix). */\nfunction startGenAiSpan(operation: string, suffix: string | undefined, attributes: Attributes): Span {\n return startInactiveSpan({\n name: suffix ? `${operation} ${suffix}` : operation,\n op: `gen_ai.${operation}`,\n attributes: { [GEN_AI_OPERATION_NAME]: operation, ...attributes },\n });\n}\n\nfunction buildInvokeAgentSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n isStream: boolean,\n): Span {\n const functionId = asString(event.functionId);\n const operationId = asString(event.operationId) ?? (isStream ? 'ai.streamText' : 'ai.generateText');\n if (callId) {\n operationIdByCallId.set(callId, { operationId, isStream });\n }\n return startGenAiSpan(GEN_AI_INVOKE_AGENT_SPAN_OP, functionId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n [GEN_AI_RESPONSE_STREAMING]: isStream,\n ...(functionId ? { [GEN_AI_FUNCTION_ID]: functionId } : {}),\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n });\n}\n\nfunction buildModelCallSpan(\n event: Record<string, unknown>,\n baseAttributes: Attributes,\n recordInputs: boolean,\n enableTruncation: boolean,\n callId: string | undefined,\n modelId: string | undefined,\n): Span {\n const parent = callId ? operationIdByCallId.get(callId) : undefined;\n const operationId = parent\n ? `${parent.operationId}.${parent.isStream ? 'doStream' : 'doGenerate'}`\n : 'ai.generateText.doGenerate';\n return startGenAiSpan(GEN_AI_GENERATE_CONTENT_OPERATION, modelId, {\n ...baseAttributes,\n [VERCEL_AI_OPERATION_ID_ATTRIBUTE]: operationId,\n ...(recordInputs ? buildInputMessageAttributes(event, enableTruncation) : {}),\n ...(recordInputs && Array.isArray(event.tools)\n ? { [GEN_AI_REQUEST_AVAILABLE_TOOLS]: safeStringify(event.tools) }\n : {}),\n });\n}\n\nfunction buildToolSpan(event: Record<string, unknown>, recordInputs: boolean): Span {\n const toolCall = isRecord(event.toolCall) ? event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(event.toolCallId) ?? asString(toolCall.toolCallId);\n const toolInput = toolCall.input ?? toolCall.args;\n // The `executeTool` event has no description; backfill it from the operation's recorded tools.\n // Gated on `recordInputs` to match the OTel path (descriptions come from the recorded tools list).\n const description =\n recordInputs && toolName ? resolveToolDescription(asString(event.callId), toolName, event.tools) : undefined;\n return startGenAiSpan(GEN_AI_EXECUTE_TOOL_SPAN_OP, toolName, {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [GEN_AI_TOOL_TYPE]: 'function',\n ...(toolName ? { [GEN_AI_TOOL_NAME]: toolName } : {}),\n ...(toolCallId ? { [GEN_AI_TOOL_CALL_ID_ATTRIBUTE]: toolCallId } : {}),\n ...(description ? { [GEN_AI_TOOL_DESCRIPTION_ATTRIBUTE]: description } : {}),\n ...(recordInputs && toolInput !== undefined ? { [GEN_AI_TOOL_INPUT]: safeStringify(toolInput) } : {}),\n });\n}\n\n/**\n * Best-effort enrichment from the resolved value the AI SDK attaches to the channel context.\n * Everything here is guarded: when a field is missing or the shape differs across `ai` versions,\n * we simply don't set the attribute rather than emit a malformed span.\n */\nexport function enrichSpanOnEnd(\n span: Span,\n data: VercelAiChannelMessage,\n channelOptions: VercelAiChannelOptions,\n): void {\n const { type, result } = data;\n if (!isRecord(result)) {\n return;\n }\n\n const { recordOutputs } = getRecordingOptions(data.event, channelOptions);\n\n if (type === 'executeTool') {\n if (recordOutputs) {\n span.setAttribute(GEN_AI_TOOL_OUTPUT, safeStringify(result.output ?? result));\n }\n // From V5 on, tool errors are not rejected (so the `error` channel verb never fires) — they\n // surface as `tool-error` content on the resolved result. Mirror the OTel path by marking the\n // span and capturing the error.\n const output = isRecord(result.output) ? result.output : undefined;\n if (output?.type === 'tool-error') {\n captureToolError(span, data, output.error);\n }\n return;\n }\n\n // `languageModelCall` results report usage as `{ total }` objects; top-level/step results report\n // flat numbers. `tokenCount` handles both.\n const usage = isRecord(result.usage) ? result.usage : undefined;\n if (usage) {\n const inputTokens = tokenCount(usage.inputTokens) ?? tokenCount(usage.tokens);\n const outputTokens = tokenCount(usage.outputTokens);\n const totalTokens = tokenCount(usage.totalTokens) ?? sum(inputTokens, outputTokens);\n if (inputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_INPUT_TOKENS, inputTokens);\n }\n if (outputTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_OUTPUT_TOKENS, outputTokens);\n }\n if (totalTokens !== undefined) {\n span.setAttribute(GEN_AI_USAGE_TOTAL_TOKENS, totalTokens);\n }\n }\n\n // Match the OTel integration: finish reasons live on the model-call (`generate_content`) span, not\n // on the top-level `invoke_agent` span.\n const finishReason = getFinishReason(result);\n if (finishReason && type === 'languageModelCall') {\n span.setAttribute(GEN_AI_RESPONSE_FINISH_REASONS, safeStringify([finishReason]));\n }\n\n const response = isRecord(result.response) ? result.response : undefined;\n const responseId = asString(response?.id) ?? asString(result.responseId);\n if (responseId) {\n span.setAttribute(GEN_AI_RESPONSE_ID, responseId);\n }\n const responseModel = asString(response?.modelId) ?? asString(data.event.modelId);\n if (responseModel) {\n span.setAttribute(GEN_AI_RESPONSE_MODEL, responseModel);\n }\n\n // Provider-specific cache/reasoning/prediction token breakdowns and `gen_ai.conversation.id`.\n // The channel exposes `providerMetadata` as an object (the OTel path parses it from a string);\n // both share `getProviderMetadataAttributes` so the emitted shape is identical.\n const providerMetadata = (result as { providerMetadata?: unknown }).providerMetadata;\n const providerAttributes = getProviderMetadataAttributes(providerMetadata);\n // Don't overwrite a conversation id already set on span start (e.g. by `conversationIdIntegration`\n // from a user-set scope value); the provider-derived id is only a fallback. Matches the OTel path.\n if (\n GEN_AI_CONVERSATION_ID_ATTRIBUTE in providerAttributes &&\n spanToJSON(span).data[GEN_AI_CONVERSATION_ID_ATTRIBUTE]\n ) {\n // oxlint-disable-next-line typescript/no-dynamic-delete\n delete providerAttributes[GEN_AI_CONVERSATION_ID_ATTRIBUTE];\n }\n span.setAttributes(providerAttributes);\n\n if (recordOutputs) {\n // `languageModelCall` exposes the response as a `content` parts array; top-level results expose\n // `text` + `toolCalls`. Both normalize into the OTel `gen_ai.output.messages` assistant message.\n const parts =\n type === 'languageModelCall' && Array.isArray(result.content)\n ? partsFromContent(result.content)\n : partsFromTextAndToolCalls(result.text, result.toolCalls);\n const outputMessages = buildOutputMessages(parts, finishReason);\n if (outputMessages) {\n span.setAttribute(GEN_AI_OUTPUT_MESSAGES, outputMessages);\n }\n }\n}\n\n/** Maps a Vercel AI finish reason to the OTel `gen_ai.output.messages` form (`tool-calls` → `tool_call`). */\nfunction normalizeFinishReason(finishReason: string | undefined): string {\n return finishReason === 'tool-calls' ? 'tool_call' : (finishReason ?? 'stop');\n}\n\n/** Reads the finish reason from a result — a string on top-level results, `{ unified }` on model calls. */\nfunction getFinishReason(result: Record<string, unknown>): string | undefined {\n const finishReason = result.finishReason;\n if (typeof finishReason === 'string') {\n return finishReason;\n }\n return isRecord(finishReason) ? asString(finishReason.unified) : undefined;\n}\n\n/** Reads a token count that may be a plain number or a `{ total }` object (model-call usage). */\nfunction tokenCount(value: unknown): number | undefined {\n return asNumber(value) ?? (isRecord(value) ? asNumber(value.total) : undefined);\n}\n\nfunction buildOutputMessages(\n parts: Array<Record<string, unknown>>,\n finishReason: string | undefined,\n): string | undefined {\n if (!parts.length) {\n return undefined;\n }\n return safeStringify([{ role: 'assistant', parts, finish_reason: normalizeFinishReason(finishReason) }]);\n}\n\nfunction toolCallPart(toolCall: Record<string, unknown>): Record<string, unknown> {\n const args = toolCall.input ?? toolCall.args;\n return {\n type: 'tool_call',\n id: asString(toolCall.toolCallId),\n name: asString(toolCall.toolName),\n arguments: typeof args === 'string' ? args : safeStringify(args ?? {}),\n };\n}\n\nfunction partsFromContent(content: unknown[]): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n for (const item of content) {\n if (!isRecord(item)) {\n continue;\n }\n if (item.type === 'text' && typeof item.text === 'string') {\n parts.push({ type: 'text', content: item.text });\n } else if (item.type === 'tool-call') {\n parts.push(toolCallPart(item));\n }\n }\n return parts;\n}\n\nfunction partsFromTextAndToolCalls(text: unknown, toolCalls: unknown): Array<Record<string, unknown>> {\n const parts: Array<Record<string, unknown>> = [];\n if (typeof text === 'string' && text.length) {\n parts.push({ type: 'text', content: text });\n }\n if (Array.isArray(toolCalls)) {\n for (const toolCall of toolCalls) {\n if (isRecord(toolCall)) {\n parts.push(toolCallPart(toolCall));\n }\n }\n }\n return parts;\n}\n\nfunction captureToolError(span: Span, data: VercelAiChannelMessage, error: unknown): void {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: error instanceof Error ? error.message : 'tool_error',\n });\n\n const toolCall = isRecord(data.event.toolCall) ? data.event.toolCall : {};\n const toolName = asString(toolCall.toolName);\n const toolCallId = asString(data.event.toolCallId) ?? asString(toolCall.toolCallId);\n\n withScope(scope => {\n scope.setContext('trace', spanToTraceContext(span));\n if (toolName) {\n scope.setTag('vercel.ai.tool.name', toolName);\n }\n if (toolCallId) {\n scope.setTag('vercel.ai.tool.callId', toolCallId);\n }\n scope.setLevel('error');\n captureException(\n error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Tool execution failed'),\n {\n mechanism: { type: 'auto.vercelai.channel', handled: false },\n },\n );\n });\n}\n\nfunction getRecordingOptions(\n event: Record<string, unknown>,\n channelOptions: VercelAiChannelOptions,\n): {\n recordInputs: boolean;\n recordOutputs: boolean;\n enableTruncation: boolean;\n} {\n const genAI = getClient()?.getDataCollectionOptions().genAI;\n\n return {\n recordInputs: resolveRecording(channelOptions.recordInputs, event.recordInputs, genAI?.inputs),\n recordOutputs: resolveRecording(channelOptions.recordOutputs, event.recordOutputs, genAI?.outputs),\n enableTruncation: shouldEnableTruncation(channelOptions.enableTruncation),\n };\n}\n\n/**\n * Mirrors the OTel integration's `determineRecordingSettings` precedence: an integration-level option\n * wins, then the per-call `experimental_telemetry.recordInputs/recordOutputs` flag the AI SDK forwards\n * on the channel event, then the global `dataCollection.genAI` default.\n *\n * NOTE: the OTel integration also defaults recording to `true` for a call with\n * `experimental_telemetry: { isEnabled: true }`. The `ai:telemetry` channel does not expose `isEnabled`\n * (nor a resolved recording flag), so that per-call default cannot be reproduced here — v7 users who\n * want inputs/outputs recorded must enable `dataCollection.genAI` or set `recordInputs`/`recordOutputs`.\n */\nfunction resolveRecording(integrationOption: unknown, perCallOption: unknown, globalDefault: unknown): boolean {\n if (typeof integrationOption === 'boolean') {\n return integrationOption;\n }\n if (typeof perCallOption === 'boolean') {\n return perCallOption;\n }\n return globalDefault === true;\n}\n\nfunction buildInputMessageAttributes(\n event: Record<string, unknown>,\n enableTruncation: boolean,\n): Record<string, string | number> {\n const attributes: Record<string, string | number> = {};\n\n // `ai` >= 7 forbids system messages in `messages`/`prompt` and exposes the system prompt as a\n // separate `instructions` field. The OTel path lifts the system message out of the prompt into\n // `gen_ai.system_instructions` as `[{ type: 'text', content }]`; mirror that shape here.\n const instructions = asString(event.instructions);\n if (instructions) {\n attributes[GEN_AI_SYSTEM_INSTRUCTIONS_ATTRIBUTE] = safeStringify([{ type: 'text', content: instructions }]);\n }\n\n // The AI SDK start events extend `StandardizedPrompt`; messages live on `messages`, otherwise the\n // simpler `prompt` field is used.\n const messages = event.messages ?? event.prompt;\n if (messages !== undefined) {\n attributes[GEN_AI_INPUT_MESSAGES] = enableTruncation ? getTruncatedJsonString(messages) : safeStringify(messages);\n // The original (pre-truncation) message count, so the product can show how many were dropped.\n attributes[GEN_AI_INPUT_MESSAGES_ORIGINAL_LENGTH_ATTRIBUTE] = Array.isArray(messages) ? messages.length : 1;\n }\n\n return attributes;\n}\n\nfunction asString(value: unknown): string | undefined {\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction asNumber(value: unknown): number | undefined {\n return typeof value === 'number' && !isNaN(value) ? value : undefined;\n}\n\nfunction sum(a: number | undefined, b: number | undefined): number | undefined {\n return a === undefined && b === undefined ? undefined : (a ?? 0) + (b ?? 0);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null;\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value);\n } catch {\n return '[unserializable]';\n }\n}\n"],"names":[],"mappings":"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"} |
@@ -7,4 +7,6 @@ /// <reference path="./node-diagnostics-channel.d.ts" /> | ||
| */ | ||
| export { mongooseIntegration } from './mongoose'; | ||
| export { IOREDIS_DC_CHANNEL_COMMAND, IOREDIS_DC_CHANNEL_CONNECT, REDIS_DC_CHANNEL_BATCH, REDIS_DC_CHANNEL_COMMAND, REDIS_DC_CHANNEL_CONNECT, subscribeRedisDiagnosticChannels, } from './redis/redis-dc-subscriber'; | ||
| export { IORedisCommandData, RedisBatchData, RedisCommandData, RedisConnectData, RedisDiagnosticChannelResponseHook, RedisTracingChannelFactory, } from './redis/redis-dc-subscriber'; | ||
| export { defaultDbStatementSerializer } from './redis/redis-statement-serializer'; | ||
| export { bindTracingChannelToSpan } from './tracing-channel'; | ||
@@ -11,0 +13,0 @@ export { SentryTracingChannel, TracingChannelLifeCycleOptions, TracingChannelBindingHandle, TracingChannelPayloadWithSpan, } from './tracing-channel'; |
@@ -15,6 +15,26 @@ /** | ||
| export declare const CHANNELS: { | ||
| readonly HAPI_ROUTE: "orchestrion:@hapi/hapi:route"; | ||
| readonly HAPI_EXT: "orchestrion:@hapi/hapi:ext"; | ||
| readonly VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText"; | ||
| readonly VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText"; | ||
| readonly VERCEL_AI_EMBED: "orchestrion:ai:embed"; | ||
| readonly VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany"; | ||
| readonly VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall"; | ||
| readonly VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel"; | ||
| readonly ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat"; | ||
| readonly ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models"; | ||
| readonly ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream"; | ||
| readonly OPENAI_CHAT: "orchestrion:openai:chat"; | ||
| readonly OPENAI_RESPONSES: "orchestrion:openai:responses"; | ||
| readonly OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings"; | ||
| readonly OPENAI_CONVERSATIONS: "orchestrion:openai:conversations"; | ||
| readonly PG_QUERY: "orchestrion:pg:query"; | ||
| readonly PG_CONNECT: "orchestrion:pg:connect"; | ||
| readonly PGPOOL_CONNECT: "orchestrion:pg-pool:connect"; | ||
| readonly IOREDIS_COMMAND: "orchestrion:ioredis:command"; | ||
| readonly IOREDIS_CONNECT: "orchestrion:ioredis:connect"; | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| readonly MYSQL_QUERY: "orchestrion:mysql:query"; | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| }; | ||
| export type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS]; | ||
| //# sourceMappingURL=channels.d.ts.map |
@@ -8,2 +8,12 @@ declare global { | ||
| /** | ||
| * Whether orchestrion has injected the diagnostics channels into this process, | ||
| * either by the runtime `--import` hook / init-time registration (`runtime`) | ||
| * or a bundler plugin (`bundler`). Both injectors set a flag on the | ||
| * `globalThis.__SENTRY_ORCHESTRION__` marker. | ||
| * | ||
| * Use this to avoid wiring up channel-subscriber integrations when nothing | ||
| * will ever publish to those channels. | ||
| */ | ||
| export declare function isOrchestrionInjected(): boolean; | ||
| /** | ||
| * Verifies that the diagnostics channels have been injected either by the | ||
@@ -10,0 +20,0 @@ * runtime `--import` hook (or init-time registration), a bundler plugin, or |
@@ -1,4 +0,54 @@ | ||
| export { detectOrchestrionSetup } from './detect'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| import { anthropicChannelIntegration } from '../integrations/tracing-channel/anthropic'; | ||
| import { hapiChannelIntegration } from '../integrations/tracing-channel/hapi'; | ||
| import { ioredisChannelIntegration } from '../integrations/tracing-channel/ioredis'; | ||
| import { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| import { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| import { openaiChannelIntegration } from '../integrations/tracing-channel/openai'; | ||
| import { postgresChannelIntegration } from '../integrations/tracing-channel/postgres'; | ||
| import { vercelAiChannelIntegration } from '../integrations/tracing-channel/vercel-ai'; | ||
| export { detectOrchestrionSetup, isOrchestrionInjected } from './detect'; | ||
| export { anthropicChannelIntegration, hapiChannelIntegration, ioredisChannelIntegration, lruMemoizerChannelIntegration, mysqlChannelIntegration, openaiChannelIntegration, postgresChannelIntegration, vercelAiChannelIntegration, }; | ||
| export { IORedisChannelIntegrationOptions, IORedisResponseHook } from '../integrations/tracing-channel/ioredis'; | ||
| /** | ||
| * The canonical set of orchestrion diagnostics-channel integrations, keyed by their public | ||
| * (OTel-parity) factory name. | ||
| * | ||
| * Single source of truth: add a new channel integration here and every consumer — the `@sentry/node` | ||
| * opt-in helper (`experimentalUseDiagnosticsChannelInjection`) and its public | ||
| * `diagnosticsChannelInjectionIntegrations()` map — picks it up automatically, so there's no separate | ||
| * list to keep in sync. | ||
| * | ||
| * NOTE: `ioredisChannelIntegration` is intentionally NOT here. It only partially replaces the | ||
| * composite OTel `Redis` integration and needs the node SDK's redis cache `responseHook` (which | ||
| * can't live in `server-utils`), so `@sentry/node` wires it up separately. | ||
| */ | ||
| export declare const channelIntegrations: { | ||
| readonly postgresIntegration: (options?: { | ||
| ignoreConnectSpans?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "Postgres"; | ||
| }; | ||
| readonly mysqlIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Mysql"; | ||
| }; | ||
| readonly lruMemoizerIntegration: () => import("@sentry/core").Integration & { | ||
| name: "LruMemoizer"; | ||
| }; | ||
| readonly openaiIntegration: (options?: import("@sentry/core").OpenAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "OpenAI"; | ||
| }; | ||
| readonly anthropicIntegration: (options?: import("@sentry/core").AnthropicAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "Anthropic_AI"; | ||
| }; | ||
| readonly vercelAiIntegration: (options?: { | ||
| recordInputs?: boolean; | ||
| recordOutputs?: boolean; | ||
| enableTruncation?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| readonly hapiIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Hapi"; | ||
| }; | ||
| }; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -5,4 +5,11 @@ import { Span } from '@sentry/core'; | ||
| export declare function clearOperationId(data: VercelAiChannelMessage): void; | ||
| /** | ||
| * Drop the per-operation `callId` maps for a single id. The v6 orchestrion adapter uses this to clear a | ||
| * `streamText` operation only after its lazily-run model call settles — the operation's own span ends | ||
| * synchronously (when `streamText` returns) but the model call runs later as the stream is consumed, and | ||
| * it still needs the operation's `operationId`/`isStream` entry to name itself `ai.streamText.doStream`. | ||
| */ | ||
| export declare function clearOperationCallId(callId: string): void; | ||
| /** The lifecycle event types the `ai:telemetry` channel can carry. */ | ||
| export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'rerank'; | ||
| export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'embedMany' | 'rerank'; | ||
| /** | ||
@@ -29,5 +36,5 @@ * The context object the AI SDK passes through one tracing-channel call. It is the same object | ||
| */ | ||
| type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| export type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| /** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */ | ||
| interface VercelAiChannelOptions { | ||
| export interface VercelAiChannelOptions { | ||
| recordInputs?: boolean; | ||
@@ -63,3 +70,2 @@ recordOutputs?: boolean; | ||
| export declare function enrichSpanOnEnd(span: Span, data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): void; | ||
| export {}; | ||
| //# sourceMappingURL=vercel-ai-dc-subscriber.d.ts.map |
@@ -6,4 +6,6 @@ /** | ||
| */ | ||
| export { mongooseIntegration } from './mongoose'; | ||
| export { IOREDIS_DC_CHANNEL_COMMAND, IOREDIS_DC_CHANNEL_CONNECT, REDIS_DC_CHANNEL_BATCH, REDIS_DC_CHANNEL_COMMAND, REDIS_DC_CHANNEL_CONNECT, subscribeRedisDiagnosticChannels, } from './redis/redis-dc-subscriber'; | ||
| export type { IORedisCommandData, RedisBatchData, RedisCommandData, RedisConnectData, RedisDiagnosticChannelResponseHook, RedisTracingChannelFactory, } from './redis/redis-dc-subscriber'; | ||
| export { defaultDbStatementSerializer } from './redis/redis-statement-serializer'; | ||
| export { bindTracingChannelToSpan } from './tracing-channel'; | ||
@@ -10,0 +12,0 @@ export type { SentryTracingChannel, TracingChannelLifeCycleOptions, TracingChannelBindingHandle, TracingChannelPayloadWithSpan, } from './tracing-channel'; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,kBAAkB,EAElB,kBAAkB,EAElB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACjD,OAAO,EACL,0BAA0B,EAC1B,0BAA0B,EAC1B,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EACxB,gCAAgC,GACjC,MAAM,6BAA6B,CAAC;AACrC,YAAY,EACV,kBAAkB,EAClB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,kCAAkC,EAClC,0BAA0B,GAC3B,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,4BAA4B,EAAE,MAAM,oCAAoC,CAAC;AAClF,OAAO,EAAE,wBAAwB,EAAE,MAAM,mBAAmB,CAAC;AAC7D,YAAY,EACV,oBAAoB,EACpB,8BAA8B,EAC9B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD,OAAO,EACL,kBAAkB,EAElB,kBAAkB,EAElB,iBAAiB,GAClB,MAAM,wCAAwC,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"names":[],"mappings":"AAuKA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;CAA8C,CAAC"} | ||
| {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"names":[],"mappings":"AAyKA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;CAA8C,CAAC"} |
@@ -15,6 +15,26 @@ /** | ||
| export declare const CHANNELS: { | ||
| readonly HAPI_ROUTE: "orchestrion:@hapi/hapi:route"; | ||
| readonly HAPI_EXT: "orchestrion:@hapi/hapi:ext"; | ||
| readonly VERCEL_AI_GENERATE_TEXT: "orchestrion:ai:generateText"; | ||
| readonly VERCEL_AI_STREAM_TEXT: "orchestrion:ai:streamText"; | ||
| readonly VERCEL_AI_EMBED: "orchestrion:ai:embed"; | ||
| readonly VERCEL_AI_EMBED_MANY: "orchestrion:ai:embedMany"; | ||
| readonly VERCEL_AI_EXECUTE_TOOL_CALL: "orchestrion:ai:executeToolCall"; | ||
| readonly VERCEL_AI_RESOLVE_LANGUAGE_MODEL: "orchestrion:ai:resolveLanguageModel"; | ||
| readonly ANTHROPIC_CHAT: "orchestrion:@anthropic-ai/sdk:chat"; | ||
| readonly ANTHROPIC_MODELS: "orchestrion:@anthropic-ai/sdk:models"; | ||
| readonly ANTHROPIC_MESSAGES_STREAM: "orchestrion:@anthropic-ai/sdk:messages-stream"; | ||
| readonly OPENAI_CHAT: "orchestrion:openai:chat"; | ||
| readonly OPENAI_RESPONSES: "orchestrion:openai:responses"; | ||
| readonly OPENAI_EMBEDDINGS: "orchestrion:openai:embeddings"; | ||
| readonly OPENAI_CONVERSATIONS: "orchestrion:openai:conversations"; | ||
| readonly PG_QUERY: "orchestrion:pg:query"; | ||
| readonly PG_CONNECT: "orchestrion:pg:connect"; | ||
| readonly PGPOOL_CONNECT: "orchestrion:pg-pool:connect"; | ||
| readonly IOREDIS_COMMAND: "orchestrion:ioredis:command"; | ||
| readonly IOREDIS_CONNECT: "orchestrion:ioredis:connect"; | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| readonly MYSQL_QUERY: "orchestrion:mysql:query"; | ||
| readonly LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load"; | ||
| }; | ||
| export type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS]; | ||
| //# sourceMappingURL=channels.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/channels.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"} | ||
| {"version":3,"file":"channels.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/channels.ts"],"names":[],"mappings":"AASA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ;;;;;;;;;;;;;;;;;;;;;;;CASX,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"} |
@@ -8,2 +8,12 @@ declare global { | ||
| /** | ||
| * Whether orchestrion has injected the diagnostics channels into this process, | ||
| * either by the runtime `--import` hook / init-time registration (`runtime`) | ||
| * or a bundler plugin (`bundler`). Both injectors set a flag on the | ||
| * `globalThis.__SENTRY_ORCHESTRION__` marker. | ||
| * | ||
| * Use this to avoid wiring up channel-subscriber integrations when nothing | ||
| * will ever publish to those channels. | ||
| */ | ||
| export declare function isOrchestrionInjected(): boolean; | ||
| /** | ||
| * Verifies that the diagnostics channels have been injected either by the | ||
@@ -10,0 +20,0 @@ * runtime `--import` hook (or init-time registration), a bundler plugin, or |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/detect.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,sBAAsB,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAiB7C"} | ||
| {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/detect.ts"],"names":[],"mappings":"AAGA,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,sBAAsB,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,IAAI,OAAO,CAG/C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAiB7C"} |
@@ -1,4 +0,54 @@ | ||
| export { detectOrchestrionSetup } from './detect'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| import { anthropicChannelIntegration } from '../integrations/tracing-channel/anthropic'; | ||
| import { hapiChannelIntegration } from '../integrations/tracing-channel/hapi'; | ||
| import { ioredisChannelIntegration } from '../integrations/tracing-channel/ioredis'; | ||
| import { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| import { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| import { openaiChannelIntegration } from '../integrations/tracing-channel/openai'; | ||
| import { postgresChannelIntegration } from '../integrations/tracing-channel/postgres'; | ||
| import { vercelAiChannelIntegration } from '../integrations/tracing-channel/vercel-ai'; | ||
| export { detectOrchestrionSetup, isOrchestrionInjected } from './detect'; | ||
| export { anthropicChannelIntegration, hapiChannelIntegration, ioredisChannelIntegration, lruMemoizerChannelIntegration, mysqlChannelIntegration, openaiChannelIntegration, postgresChannelIntegration, vercelAiChannelIntegration, }; | ||
| export type { IORedisChannelIntegrationOptions, IORedisResponseHook } from '../integrations/tracing-channel/ioredis'; | ||
| /** | ||
| * The canonical set of orchestrion diagnostics-channel integrations, keyed by their public | ||
| * (OTel-parity) factory name. | ||
| * | ||
| * Single source of truth: add a new channel integration here and every consumer — the `@sentry/node` | ||
| * opt-in helper (`experimentalUseDiagnosticsChannelInjection`) and its public | ||
| * `diagnosticsChannelInjectionIntegrations()` map — picks it up automatically, so there's no separate | ||
| * list to keep in sync. | ||
| * | ||
| * NOTE: `ioredisChannelIntegration` is intentionally NOT here. It only partially replaces the | ||
| * composite OTel `Redis` integration and needs the node SDK's redis cache `responseHook` (which | ||
| * can't live in `server-utils`), so `@sentry/node` wires it up separately. | ||
| */ | ||
| export declare const channelIntegrations: { | ||
| readonly postgresIntegration: (options?: { | ||
| ignoreConnectSpans?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "Postgres"; | ||
| }; | ||
| readonly mysqlIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Mysql"; | ||
| }; | ||
| readonly lruMemoizerIntegration: () => import("@sentry/core").Integration & { | ||
| name: "LruMemoizer"; | ||
| }; | ||
| readonly openaiIntegration: (options?: import("@sentry/core").OpenAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "OpenAI"; | ||
| }; | ||
| readonly anthropicIntegration: (options?: import("@sentry/core").AnthropicAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "Anthropic_AI"; | ||
| }; | ||
| readonly vercelAiIntegration: (options?: { | ||
| recordInputs?: boolean; | ||
| recordOutputs?: boolean; | ||
| enableTruncation?: boolean; | ||
| } | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| readonly hapiIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Hapi"; | ||
| }; | ||
| }; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAClD,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,6BAA6B,EAAE,MAAM,8CAA8C,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,2BAA2B,EAAE,MAAM,2CAA2C,CAAC;AACxF,OAAO,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AAC9E,OAAO,EAAE,yBAAyB,EAAE,MAAM,yCAAyC,CAAC;AACpF,OAAO,EAAE,6BAA6B,EAAE,MAAM,8CAA8C,CAAC;AAC7F,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAC;AAChF,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAC;AAClF,OAAO,EAAE,0BAA0B,EAAE,MAAM,0CAA0C,CAAC;AACtF,OAAO,EAAE,0BAA0B,EAAE,MAAM,2CAA2C,CAAC;AAEvF,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AACzE,OAAO,EACL,2BAA2B,EAC3B,sBAAsB,EACtB,yBAAyB,EACzB,6BAA6B,EAC7B,uBAAuB,EACvB,wBAAwB,EACxB,0BAA0B,EAC1B,0BAA0B,GAC3B,CAAC;AACF,YAAY,EAAE,gCAAgC,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAErH;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAQtB,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/runtime/register.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,sBAAsB,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mCAAmC,IAAI,IAAI,CA4F1D"} | ||
| {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../../src/orchestrion/runtime/register.ts"],"names":[],"mappings":"AAOA,OAAO,CAAC,MAAM,CAAC;IAEb,IAAI,sBAAsB,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,GAAG,SAAS,CAAC;CAClF;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mCAAmC,IAAI,IAAI,CAiG1D"} |
@@ -5,4 +5,11 @@ import type { Span } from '@sentry/core'; | ||
| export declare function clearOperationId(data: VercelAiChannelMessage): void; | ||
| /** | ||
| * Drop the per-operation `callId` maps for a single id. The v6 orchestrion adapter uses this to clear a | ||
| * `streamText` operation only after its lazily-run model call settles — the operation's own span ends | ||
| * synchronously (when `streamText` returns) but the model call runs later as the stream is consumed, and | ||
| * it still needs the operation's `operationId`/`isStream` entry to name itself `ai.streamText.doStream`. | ||
| */ | ||
| export declare function clearOperationCallId(callId: string): void; | ||
| /** The lifecycle event types the `ai:telemetry` channel can carry. */ | ||
| export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'rerank'; | ||
| export type ChannelEventType = 'generateText' | 'streamText' | 'step' | 'languageModelCall' | 'executeTool' | 'embed' | 'embedMany' | 'rerank'; | ||
| /** | ||
@@ -29,5 +36,5 @@ * The context object the AI SDK passes through one tracing-channel call. It is the same object | ||
| */ | ||
| type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| export type VercelAiTracingChannelFactory = <T extends object>(name: string) => TracingChannel<T, T>; | ||
| /** Integration-level recording options, pinned at subscribe time so we never look the integration up per event. */ | ||
| interface VercelAiChannelOptions { | ||
| export interface VercelAiChannelOptions { | ||
| recordInputs?: boolean; | ||
@@ -63,3 +70,2 @@ recordOutputs?: boolean; | ||
| export declare function enrichSpanOnEnd(span: Span, data: VercelAiChannelMessage, channelOptions: VercelAiChannelOptions): void; | ||
| export {}; | ||
| //# sourceMappingURL=vercel-ai-dc-subscriber.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAiBzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA6C/D,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CASnE;AA0CD,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,YAAY,GACZ,MAAM,GACN,mBAAmB,GACnB,aAAa,GACb,OAAO,GACP,QAAQ,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,KAAK,6BAA6B,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAE9F,mHAAmH;AACnH,UAAU,sBAAsB;IAC9B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,6BAA6B,EAC7C,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAkBN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,GAAG,SAAS,CA+ClB;AA4ED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,CAqFN"} | ||
| {"version":3,"file":"vercel-ai-dc-subscriber.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/vercel-ai-dc-subscriber.ts"],"names":[],"mappings":"AA4BA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAiBzC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AA6C/D,2GAA2G;AAC3G,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAQnE;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAGzD;AA0CD,sEAAsE;AACtE,MAAM,MAAM,gBAAgB,GACxB,cAAc,GACd,YAAY,GACZ,MAAM,GACN,mBAAmB,GACnB,aAAa,GACb,OAAO,GACP,WAAW,GACX,QAAQ,CAAC;AAEb;;;;GAIG;AACH,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,gBAAgB,CAAC;IACvB,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,6BAA6B,GAAG,CAAC,CAAC,SAAS,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AAErG,mHAAmH;AACnH,MAAM,WAAW,sBAAsB;IACrC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAID;;;;;;;;;;;GAWG;AACH,wBAAgB,+BAA+B,CAC7C,cAAc,EAAE,6BAA6B,EAC7C,OAAO,GAAE,sBAA2B,GACnC,IAAI,CAkBN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,GAAG,SAAS,CAmDlB;AA4ED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,IAAI,EACV,IAAI,EAAE,sBAAsB,EAC5B,cAAc,EAAE,sBAAsB,GACrC,IAAI,CAqFN"} |
+9
-9
| { | ||
| "name": "@sentry/server-utils", | ||
| "version": "10.63.0", | ||
| "version": "10.64.0", | ||
| "description": "Server Utilities for all Sentry JavaScript SDKs", | ||
@@ -31,5 +31,5 @@ "repository": "git://github.com/getsentry/sentry-javascript.git", | ||
| "./orchestrion/config": { | ||
| "types": "./build/types/orchestrion/config.d.ts", | ||
| "import": "./build/esm/orchestrion/config.js", | ||
| "require": "./build/cjs/orchestrion/config.js" | ||
| "types": "./build/types/orchestrion/config/index.d.ts", | ||
| "import": "./build/esm/orchestrion/config/index.js", | ||
| "require": "./build/cjs/orchestrion/config/index.js" | ||
| }, | ||
@@ -58,3 +58,3 @@ "./orchestrion/register": { | ||
| "orchestrion/config": [ | ||
| "build/types-ts3.8/orchestrion/config.d.ts" | ||
| "build/types-ts3.8/orchestrion/config/index.d.ts" | ||
| ], | ||
@@ -73,3 +73,3 @@ "orchestrion/register": [ | ||
| "orchestrion/config": [ | ||
| "build/types/orchestrion/config.d.ts" | ||
| "build/types/orchestrion/config/index.d.ts" | ||
| ], | ||
@@ -90,5 +90,5 @@ "orchestrion/register": [ | ||
| "@apm-js-collab/code-transformer": "^0.15.0", | ||
| "@apm-js-collab/tracing-hooks": "^0.10.0", | ||
| "@sentry/conventions": "^0.12.0", | ||
| "@sentry/core": "10.63.0", | ||
| "@apm-js-collab/tracing-hooks": "^0.10.1", | ||
| "@sentry/conventions": "^0.15.1", | ||
| "@sentry/core": "10.64.0", | ||
| "magic-string": "~0.30.0" | ||
@@ -95,0 +95,0 @@ }, |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const SENTRY_INSTRUMENTATIONS = [ | ||
| { | ||
| channelName: "query", | ||
| module: { name: "mysql", versionRange: ">=2.0.0 <3", filePath: "lib/Connection.js" }, | ||
| // `Connection` in mysql v2 is a constructor function (NOT a class): | ||
| // `function Connection(options) { ... }` | ||
| // `Connection.prototype.query = function query(sql, values, cb) { ... }` | ||
| // orchestrion's `className`+`methodName` query only matches `class` declarations. | ||
| // The named function expression on the right-hand side of the prototype | ||
| // assignment is what we want — that's matched by `expressionName: 'query'`, | ||
| // which produces the esquery selector | ||
| // `AssignmentExpression[left.property.name="query"] > FunctionExpression[async]`. | ||
| // `Auto` so both `connection.query(sql, cb)` and `connection.query(sql)` | ||
| // (streamable, no callback) get channel events. The transform picks | ||
| // `wrapCallback` when the last arg is a function and `wrapPromise` | ||
| // otherwise — for mysql's no-callback path the latter publishes | ||
| // `start`/`end` synchronously around the original call and stores the | ||
| // returned `Query` emitter on `ctx.result`, which the integration uses to | ||
| // attach `'end'`/`'error'` listeners that finish the span. | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "load", | ||
| // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0 | ||
| module: { name: "lru-memoizer", versionRange: ">=2.1.0 <4", filePath: "lib/async.js" }, | ||
| functionQuery: { functionName: "memoizedFunction", kind: "Callback" } | ||
| } | ||
| ]; | ||
| const INSTRUMENTED_MODULE_NAMES = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map((i) => i.module.name))); | ||
| function withoutInstrumentedExternals(external) { | ||
| if (!external) { | ||
| return void 0; | ||
| } | ||
| return external.filter( | ||
| (entry) => !INSTRUMENTED_MODULE_NAMES.some((name) => entry === name || entry.startsWith(`${name}/`)) | ||
| ); | ||
| } | ||
| exports.INSTRUMENTED_MODULE_NAMES = INSTRUMENTED_MODULE_NAMES; | ||
| exports.SENTRY_INSTRUMENTATIONS = SENTRY_INSTRUMENTATIONS; | ||
| exports.withoutInstrumentedExternals = withoutInstrumentedExternals; | ||
| //# sourceMappingURL=config.js.map |
| {"version":3,"file":"config.js","sources":["../../../src/orchestrion/config.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\n/**\n * The central list of channel injections orchestrion should perform.\n *\n * This module has NO side effects — it's the only thing both the runtime hook\n * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …)\n * import from. Adding a new instrumented method is one entry here plus one\n * subscriber in `integrations/<lib>/tracing-channel.ts`.\n *\n * `channelName` here is the unprefixed suffix; the actual diagnostics_channel\n * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`).\n */\nexport const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[] = [\n {\n channelName: 'query',\n module: { name: 'mysql', versionRange: '>=2.0.0 <3', filePath: 'lib/Connection.js' },\n // `Connection` in mysql v2 is a constructor function (NOT a class):\n // `function Connection(options) { ... }`\n // `Connection.prototype.query = function query(sql, values, cb) { ... }`\n // orchestrion's `className`+`methodName` query only matches `class` declarations.\n // The named function expression on the right-hand side of the prototype\n // assignment is what we want — that's matched by `expressionName: 'query'`,\n // which produces the esquery selector\n // `AssignmentExpression[left.property.name=\"query\"] > FunctionExpression[async]`.\n // `Auto` so both `connection.query(sql, cb)` and `connection.query(sql)`\n // (streamable, no callback) get channel events. The transform picks\n // `wrapCallback` when the last arg is a function and `wrapPromise`\n // otherwise — for mysql's no-callback path the latter publishes\n // `start`/`end` synchronously around the original call and stores the\n // returned `Query` emitter on `ctx.result`, which the integration uses to\n // attach `'end'`/`'error'` listeners that finish the span.\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'load',\n // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0\n module: { name: 'lru-memoizer', versionRange: '>=2.1.0 <4', filePath: 'lib/async.js' },\n functionQuery: { functionName: 'memoizedFunction', kind: 'Callback' },\n },\n];\n\n/**\n * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS`\n * (e.g. `['mysql']`).\n *\n * Bundler plugins MUST ensure these are actually bundled rather than\n * externalized: an externalized dependency is resolved from `node_modules` at\n * runtime and never passes through the code transform's `onLoad`, so its\n * diagnostics_channel calls are silently never injected.\n */\nexport const INSTRUMENTED_MODULE_NAMES: string[] = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map(i => i.module.name)));\n\n/**\n * Returns `external` with any instrumented packages removed, so a bundler that\n * uses an \"external\" denylist (esbuild, Bun, Rollup) still bundles — and thus\n * transforms — them. Matches an exact package name (`'mysql'`) or a subpath\n * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined`\n * is returned unchanged.\n *\n * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes\n * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.)\n */\nexport function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined {\n if (!external) {\n return undefined;\n }\n return external.filter(\n entry => !INSTRUMENTED_MODULE_NAMES.some(name => entry === name || entry.startsWith(`${name}/`)),\n );\n}\n"],"names":[],"mappings":";;AAaO,MAAM,uBAAA,GAAmD;AAAA,EAC9D;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,SAAS,YAAA,EAAc,YAAA,EAAc,UAAU,mBAAA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO,GACzD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,MAAA;AAAA;AAAA,IAEb,QAAQ,EAAE,IAAA,EAAM,gBAAgB,YAAA,EAAc,YAAA,EAAc,UAAU,cAAA,EAAe;AAAA,IACrF,aAAA,EAAe,EAAE,YAAA,EAAc,kBAAA,EAAoB,MAAM,UAAA;AAAW;AAExE;AAWO,MAAM,yBAAA,GAAsC,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,uBAAA,CAAwB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,CAAO,IAAI,CAAC,CAAC;AAY/G,SAAS,6BAA6B,QAAA,EAA+D;AAC1G,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAA,KAAA,KAAS,CAAC,yBAAA,CAA0B,IAAA,CAAK,CAAA,IAAA,KAAQ,KAAA,KAAU,IAAA,IAAQ,KAAA,CAAM,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAC;AAAA,GACjG;AACF;;;;;;"} |
| const SENTRY_INSTRUMENTATIONS = [ | ||
| { | ||
| channelName: "query", | ||
| module: { name: "mysql", versionRange: ">=2.0.0 <3", filePath: "lib/Connection.js" }, | ||
| // `Connection` in mysql v2 is a constructor function (NOT a class): | ||
| // `function Connection(options) { ... }` | ||
| // `Connection.prototype.query = function query(sql, values, cb) { ... }` | ||
| // orchestrion's `className`+`methodName` query only matches `class` declarations. | ||
| // The named function expression on the right-hand side of the prototype | ||
| // assignment is what we want — that's matched by `expressionName: 'query'`, | ||
| // which produces the esquery selector | ||
| // `AssignmentExpression[left.property.name="query"] > FunctionExpression[async]`. | ||
| // `Auto` so both `connection.query(sql, cb)` and `connection.query(sql)` | ||
| // (streamable, no callback) get channel events. The transform picks | ||
| // `wrapCallback` when the last arg is a function and `wrapPromise` | ||
| // otherwise — for mysql's no-callback path the latter publishes | ||
| // `start`/`end` synchronously around the original call and stores the | ||
| // returned `Query` emitter on `ctx.result`, which the integration uses to | ||
| // attach `'end'`/`'error'` listeners that finish the span. | ||
| functionQuery: { expressionName: "query", kind: "Auto" } | ||
| }, | ||
| { | ||
| channelName: "load", | ||
| // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0 | ||
| module: { name: "lru-memoizer", versionRange: ">=2.1.0 <4", filePath: "lib/async.js" }, | ||
| functionQuery: { functionName: "memoizedFunction", kind: "Callback" } | ||
| } | ||
| ]; | ||
| const INSTRUMENTED_MODULE_NAMES = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map((i) => i.module.name))); | ||
| function withoutInstrumentedExternals(external) { | ||
| if (!external) { | ||
| return void 0; | ||
| } | ||
| return external.filter( | ||
| (entry) => !INSTRUMENTED_MODULE_NAMES.some((name) => entry === name || entry.startsWith(`${name}/`)) | ||
| ); | ||
| } | ||
| export { INSTRUMENTED_MODULE_NAMES, SENTRY_INSTRUMENTATIONS, withoutInstrumentedExternals }; | ||
| //# sourceMappingURL=config.js.map |
| {"version":3,"file":"config.js","sources":["../../../src/orchestrion/config.ts"],"sourcesContent":["import type { InstrumentationConfig } from '@apm-js-collab/code-transformer';\n\n/**\n * The central list of channel injections orchestrion should perform.\n *\n * This module has NO side effects — it's the only thing both the runtime hook\n * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …)\n * import from. Adding a new instrumented method is one entry here plus one\n * subscriber in `integrations/<lib>/tracing-channel.ts`.\n *\n * `channelName` here is the unprefixed suffix; the actual diagnostics_channel\n * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`).\n */\nexport const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[] = [\n {\n channelName: 'query',\n module: { name: 'mysql', versionRange: '>=2.0.0 <3', filePath: 'lib/Connection.js' },\n // `Connection` in mysql v2 is a constructor function (NOT a class):\n // `function Connection(options) { ... }`\n // `Connection.prototype.query = function query(sql, values, cb) { ... }`\n // orchestrion's `className`+`methodName` query only matches `class` declarations.\n // The named function expression on the right-hand side of the prototype\n // assignment is what we want — that's matched by `expressionName: 'query'`,\n // which produces the esquery selector\n // `AssignmentExpression[left.property.name=\"query\"] > FunctionExpression[async]`.\n // `Auto` so both `connection.query(sql, cb)` and `connection.query(sql)`\n // (streamable, no callback) get channel events. The transform picks\n // `wrapCallback` when the last arg is a function and `wrapPromise`\n // otherwise — for mysql's no-callback path the latter publishes\n // `start`/`end` synchronously around the original call and stores the\n // returned `Query` emitter on `ctx.result`, which the integration uses to\n // attach `'end'`/`'error'` listeners that finish the span.\n functionQuery: { expressionName: 'query', kind: 'Auto' },\n },\n {\n channelName: 'load',\n // `>=2.1.0` only: the named `function memoizedFunction()` the selector targets exists from 2.1.0\n module: { name: 'lru-memoizer', versionRange: '>=2.1.0 <4', filePath: 'lib/async.js' },\n functionQuery: { functionName: 'memoizedFunction', kind: 'Callback' },\n },\n];\n\n/**\n * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS`\n * (e.g. `['mysql']`).\n *\n * Bundler plugins MUST ensure these are actually bundled rather than\n * externalized: an externalized dependency is resolved from `node_modules` at\n * runtime and never passes through the code transform's `onLoad`, so its\n * diagnostics_channel calls are silently never injected.\n */\nexport const INSTRUMENTED_MODULE_NAMES: string[] = Array.from(new Set(SENTRY_INSTRUMENTATIONS.map(i => i.module.name)));\n\n/**\n * Returns `external` with any instrumented packages removed, so a bundler that\n * uses an \"external\" denylist (esbuild, Bun, Rollup) still bundles — and thus\n * transforms — them. Matches an exact package name (`'mysql'`) or a subpath\n * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined`\n * is returned unchanged.\n *\n * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes\n * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.)\n */\nexport function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined {\n if (!external) {\n return undefined;\n }\n return external.filter(\n entry => !INSTRUMENTED_MODULE_NAMES.some(name => entry === name || entry.startsWith(`${name}/`)),\n );\n}\n"],"names":[],"mappings":"AAaO,MAAM,uBAAA,GAAmD;AAAA,EAC9D;AAAA,IACE,WAAA,EAAa,OAAA;AAAA,IACb,QAAQ,EAAE,IAAA,EAAM,SAAS,YAAA,EAAc,YAAA,EAAc,UAAU,mBAAA,EAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAgBnF,aAAA,EAAe,EAAE,cAAA,EAAgB,OAAA,EAAS,MAAM,MAAA;AAAO,GACzD;AAAA,EACA;AAAA,IACE,WAAA,EAAa,MAAA;AAAA;AAAA,IAEb,QAAQ,EAAE,IAAA,EAAM,gBAAgB,YAAA,EAAc,YAAA,EAAc,UAAU,cAAA,EAAe;AAAA,IACrF,aAAA,EAAe,EAAE,YAAA,EAAc,kBAAA,EAAoB,MAAM,UAAA;AAAW;AAExE;AAWO,MAAM,yBAAA,GAAsC,KAAA,CAAM,IAAA,CAAK,IAAI,GAAA,CAAI,uBAAA,CAAwB,GAAA,CAAI,CAAA,CAAA,KAAK,CAAA,CAAE,MAAA,CAAO,IAAI,CAAC,CAAC;AAY/G,SAAS,6BAA6B,QAAA,EAA+D;AAC1G,EAAA,IAAI,CAAC,QAAA,EAAU;AACb,IAAA,OAAO,MAAA;AAAA,EACT;AACA,EAAA,OAAO,QAAA,CAAS,MAAA;AAAA,IACd,CAAA,KAAA,KAAS,CAAC,yBAAA,CAA0B,IAAA,CAAK,CAAA,IAAA,KAAQ,KAAA,KAAU,IAAA,IAAQ,KAAA,CAAM,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAC;AAAA,GACjG;AACF;;;;"} |
| import { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| /** | ||
| * The central list of channel injections orchestrion should perform. | ||
| * | ||
| * This module has NO side effects — it's the only thing both the runtime hook | ||
| * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …) | ||
| * import from. Adding a new instrumented method is one entry here plus one | ||
| * subscriber in `integrations/<lib>/tracing-channel.ts`. | ||
| * | ||
| * `channelName` here is the unprefixed suffix; the actual diagnostics_channel | ||
| * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`). | ||
| */ | ||
| export declare const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[]; | ||
| /** | ||
| * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS` | ||
| * (e.g. `['mysql']`). | ||
| * | ||
| * Bundler plugins MUST ensure these are actually bundled rather than | ||
| * externalized: an externalized dependency is resolved from `node_modules` at | ||
| * runtime and never passes through the code transform's `onLoad`, so its | ||
| * diagnostics_channel calls are silently never injected. | ||
| */ | ||
| export declare const INSTRUMENTED_MODULE_NAMES: string[]; | ||
| /** | ||
| * Returns `external` with any instrumented packages removed, so a bundler that | ||
| * uses an "external" denylist (esbuild, Bun, Rollup) still bundles — and thus | ||
| * transforms — them. Matches an exact package name (`'mysql'`) or a subpath | ||
| * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined` | ||
| * is returned unchanged. | ||
| * | ||
| * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes | ||
| * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.) | ||
| */ | ||
| export declare function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined; | ||
| //# sourceMappingURL=config.d.ts.map |
| import type { InstrumentationConfig } from '@apm-js-collab/code-transformer'; | ||
| /** | ||
| * The central list of channel injections orchestrion should perform. | ||
| * | ||
| * This module has NO side effects — it's the only thing both the runtime hook | ||
| * (`runtime/import-hook.mjs`) and the bundler plugins (`bundler/vite.ts`, …) | ||
| * import from. Adding a new instrumented method is one entry here plus one | ||
| * subscriber in `integrations/<lib>/tracing-channel.ts`. | ||
| * | ||
| * `channelName` here is the unprefixed suffix; the actual diagnostics_channel | ||
| * name is `orchestrion:${module.name}:${channelName}` (see `channels.ts`). | ||
| */ | ||
| export declare const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[]; | ||
| /** | ||
| * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS` | ||
| * (e.g. `['mysql']`). | ||
| * | ||
| * Bundler plugins MUST ensure these are actually bundled rather than | ||
| * externalized: an externalized dependency is resolved from `node_modules` at | ||
| * runtime and never passes through the code transform's `onLoad`, so its | ||
| * diagnostics_channel calls are silently never injected. | ||
| */ | ||
| export declare const INSTRUMENTED_MODULE_NAMES: string[]; | ||
| /** | ||
| * Returns `external` with any instrumented packages removed, so a bundler that | ||
| * uses an "external" denylist (esbuild, Bun, Rollup) still bundles — and thus | ||
| * transforms — them. Matches an exact package name (`'mysql'`) or a subpath | ||
| * (`'mysql/lib/...'`); wildcard/other patterns are left untouched. `undefined` | ||
| * is returned unchanged. | ||
| * | ||
| * (Vite uses an `ssr.noExternal` allowlist instead, so it consumes | ||
| * `INSTRUMENTED_MODULE_NAMES` directly rather than this helper.) | ||
| */ | ||
| export declare function withoutInstrumentedExternals(external: readonly string[] | undefined): string[] | undefined; | ||
| //# sourceMappingURL=config.d.ts.map |
| {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/orchestrion/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,iCAAiC,CAAC;AAE7E;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,EAAE,qBAAqB,EA2B1D,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,yBAAyB,EAAE,MAAM,EAAyE,CAAC;AAExH;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,SAAS,CAO1G"} |
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
Mixed license
LicensePackage contains multiple licenses.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
894712
96.05%274
104.48%7376
101.37%1
Infinity%33
83.33%+ Added
+ Added
- Removed
- Removed
Updated
Updated