@sentry/server-utils
Advanced tools
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
| const debugBuild = require('../../../debug-build.js'); | ||
| const core = require('@sentry/core'); | ||
| const utils = require('./utils.js'); | ||
| function getFastifyIntegration() { | ||
| const client = core.getClient(); | ||
| return client?.getIntegrationByName(utils.INTEGRATION_NAME); | ||
| } | ||
| function subscribeToFastifyErrorChannel() { | ||
| diagnosticsChannel.subscribe("tracing:fastify.request.handler:error", (message) => { | ||
| const { error, request, reply } = message; | ||
| handleFastifyError.call(handleFastifyError, error, request, reply, "diagnostics-channel"); | ||
| }); | ||
| } | ||
| function handleFastifyError(error, request, reply, handlerOrigin) { | ||
| const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || utils.defaultShouldHandleError; | ||
| if (handlerOrigin === "diagnostics-channel") { | ||
| this.diagnosticsChannelExists = true; | ||
| } | ||
| if (this.diagnosticsChannelExists && handlerOrigin === "onError-hook") { | ||
| debugBuild.DEBUG_BUILD && core.debug.warn( | ||
| "Fastify error handler was already registered via diagnostics channel.", | ||
| "You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options." | ||
| ); | ||
| return; | ||
| } | ||
| if (shouldHandleError(error, request, reply)) { | ||
| core.captureException(error, { | ||
| mechanism: { | ||
| handled: false, | ||
| type: "auto.function.fastify" | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| exports.handleFastifyError = handleFastifyError; | ||
| exports.subscribeToFastifyErrorChannel = subscribeToFastifyErrorChannel; | ||
| //# sourceMappingURL=errors.js.map |
| {"version":3,"file":"errors.js","sources":["../../../../../src/integrations/tracing-channel/fastify/errors.ts"],"sourcesContent":["import type { FastifyIntegration, FastifyReply, FastifyRequest } from './types';\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { DEBUG_BUILD } from '../../../debug-build';\nimport { getClient, debug, captureException } from '@sentry/core';\nimport { defaultShouldHandleError, INTEGRATION_NAME } from './utils';\n\nfunction getFastifyIntegration(): FastifyIntegration | undefined {\n const client = getClient();\n return client?.getIntegrationByName(INTEGRATION_NAME);\n}\n\n/**\n * Subscribe to the Fastify v5 error diagnostics channel.\n */\nexport function subscribeToFastifyErrorChannel(): void {\n diagnosticsChannel.subscribe('tracing:fastify.request.handler:error', message => {\n const { error, request, reply } = message as {\n error: Error;\n request: FastifyRequest;\n reply: FastifyReply;\n };\n\n handleFastifyError.call(handleFastifyError, error, request, reply, 'diagnostics-channel');\n });\n}\n\n/**\n * Handle a Fastify error, and possibly send it to Sentry.\n */\nexport function handleFastifyError(\n this: {\n diagnosticsChannelExists?: boolean;\n },\n error: Error,\n request: FastifyRequest,\n reply: FastifyReply,\n handlerOrigin: 'diagnostics-channel' | 'onError-hook',\n): void {\n const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || defaultShouldHandleError;\n // Diagnostics channel runs before the onError hook, so we can use it to check if the handler was already registered\n if (handlerOrigin === 'diagnostics-channel') {\n this.diagnosticsChannelExists = true;\n }\n\n if (this.diagnosticsChannelExists && handlerOrigin === 'onError-hook') {\n DEBUG_BUILD &&\n debug.warn(\n 'Fastify error handler was already registered via diagnostics channel.',\n 'You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options.',\n );\n\n // If the diagnostics channel already exists, we don't need to handle the error again\n return;\n }\n\n if (shouldHandleError(error, request, reply)) {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.function.fastify',\n },\n });\n }\n}\n"],"names":["getClient","INTEGRATION_NAME","defaultShouldHandleError","DEBUG_BUILD","debug","captureException"],"mappings":";;;;;;;AAMA,SAAS,qBAAA,GAAwD;AAC/D,EAAA,MAAM,SAASA,cAAA,EAAU;AACzB,EAAA,OAAO,MAAA,EAAQ,qBAAqBC,sBAAgB,CAAA;AACtD;AAKO,SAAS,8BAAA,GAAuC;AACrD,EAAA,kBAAA,CAAmB,SAAA,CAAU,yCAAyC,CAAA,OAAA,KAAW;AAC/E,IAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAM,GAAI,OAAA;AAMlC,IAAA,kBAAA,CAAmB,IAAA,CAAK,kBAAA,EAAoB,KAAA,EAAO,OAAA,EAAS,OAAO,qBAAqB,CAAA;AAAA,EAC1F,CAAC,CAAA;AACH;AAKO,SAAS,kBAAA,CAId,KAAA,EACA,OAAA,EACA,KAAA,EACA,aAAA,EACM;AACN,EAAA,MAAM,iBAAA,GAAoB,qBAAA,EAAsB,EAAG,oBAAA,EAAqB,IAAKC,8BAAA;AAE7E,EAAA,IAAI,kBAAkB,qBAAA,EAAuB;AAC3C,IAAA,IAAA,CAAK,wBAAA,GAA2B,IAAA;AAAA,EAClC;AAEA,EAAA,IAAI,IAAA,CAAK,wBAAA,IAA4B,aAAA,KAAkB,cAAA,EAAgB;AACrE,IAAAC,sBAAA,IACEC,UAAA,CAAM,IAAA;AAAA,MACJ,uEAAA;AAAA,MACA;AAAA,KACF;AAGF,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,iBAAA,CAAkB,KAAA,EAAO,OAAA,EAAS,KAAK,CAAA,EAAG;AAC5C,IAAAC,qBAAA,CAAiB,KAAA,EAAO;AAAA,MACtB,SAAA,EAAW;AAAA,QACT,OAAA,EAAS,KAAA;AAAA,QACT,IAAA,EAAM;AAAA;AACR,KACD,CAAA;AAAA,EACH;AACF;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const core = require('@sentry/core'); | ||
| const instrumentation = require('./instrumentation.js'); | ||
| const utils = require('./utils.js'); | ||
| const errors = require('./errors.js'); | ||
| const _fastifyIntegration = (({ shouldHandleError }) => { | ||
| let _shouldHandleError; | ||
| return { | ||
| name: utils.INTEGRATION_NAME, | ||
| setupOnce() { | ||
| _shouldHandleError = shouldHandleError || utils.defaultShouldHandleError; | ||
| errors.subscribeToFastifyErrorChannel(); | ||
| instrumentation.instrumentFastify(); | ||
| }, | ||
| getShouldHandleError() { | ||
| return _shouldHandleError; | ||
| }, | ||
| setShouldHandleError(shouldHandleError2) { | ||
| _shouldHandleError = shouldHandleError2; | ||
| } | ||
| }; | ||
| }); | ||
| const fastifyIntegration = core.defineIntegration( | ||
| (options = {}) => _fastifyIntegration(options) | ||
| ); | ||
| const instrumentFastify = instrumentation.instrumentFastify; | ||
| const handleFastifyError = errors.handleFastifyError; | ||
| exports.fastifyIntegration = fastifyIntegration; | ||
| exports.handleFastifyError = handleFastifyError; | ||
| exports.instrumentFastify = instrumentFastify; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing-channel/fastify/index.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\nimport type { FastifyIntegration, FastifyReply, FastifyRequest } from './types';\n\nimport { instrumentFastify as _instrumentFastify } from './instrumentation';\nimport { defaultShouldHandleError, INTEGRATION_NAME } from './utils';\nimport { subscribeToFastifyErrorChannel, handleFastifyError as _handleFastifyError } from './errors';\n\n/**\n * Options for the Fastify integration.\n *\n * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @example\n *\n * ```javascript\n * Sentry.init({\n * integrations: [\n * Sentry.fastifyIntegration({\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 500;\n * },\n * });\n * },\n * });\n * ```\n *\n */\ninterface FastifyIntegrationOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n */\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n}\n\nconst _fastifyIntegration = (({ shouldHandleError }: Partial<FastifyIntegrationOptions>) => {\n let _shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n _shouldHandleError = shouldHandleError || defaultShouldHandleError;\n\n subscribeToFastifyErrorChannel();\n _instrumentFastify();\n },\n getShouldHandleError() {\n return _shouldHandleError;\n },\n setShouldHandleError(shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean) {\n _shouldHandleError = shouldHandleError;\n },\n } satisfies FastifyIntegration;\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).\n * This integration supports Fastify v5 only.\n *\n * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.fastifyIntegration()],\n * })\n * ```\n */\nexport const fastifyIntegration = defineIntegration((options: Partial<FastifyIntegrationOptions> = {}) =>\n _fastifyIntegration(options),\n);\n\n/**\n * @deprecated This export is deprecated and will not longer be exposed in the next major version.\n */\nexport const instrumentFastify = _instrumentFastify;\n\n/**\n * @deprecated This export is deprecated and will not longer be exposed in the next major version.\n */\nexport const handleFastifyError = _handleFastifyError;\n"],"names":["INTEGRATION_NAME","defaultShouldHandleError","subscribeToFastifyErrorChannel","_instrumentFastify","shouldHandleError","defineIntegration","_handleFastifyError"],"mappings":";;;;;;;AA2CA,MAAM,mBAAA,IAAuB,CAAC,EAAE,iBAAA,EAAkB,KAA0C;AAC1F,EAAA,IAAI,kBAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA,EAAMA,sBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,kBAAA,GAAqB,iBAAA,IAAqBC,8BAAA;AAE1C,MAAAC,qCAAA,EAA+B;AAC/B,MAAAC,iCAAA,EAAmB;AAAA,IACrB,CAAA;AAAA,IACA,oBAAA,GAAuB;AACrB,MAAA,OAAO,kBAAA;AAAA,IACT,CAAA;AAAA,IACA,qBAAqBC,kBAAAA,EAA4F;AAC/G,MAAA,kBAAA,GAAqBA,kBAAAA;AAAA,IACvB;AAAA,GACF;AACF,CAAA,CAAA;AAiBO,MAAM,kBAAA,GAAqBC,sBAAA;AAAA,EAAkB,CAAC,OAAA,GAA8C,EAAC,KAClG,oBAAoB,OAAO;AAC7B;AAKO,MAAM,iBAAA,GAAoBF;AAK1B,MAAM,kBAAA,GAAqBG;;;;;;"} |
| 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 PACKAGE_NAME = "@sentry/instrumentation-fastify"; | ||
| const SUPPORTED_VERSIONS = ">=3.21.0 <6"; | ||
| const ORIGIN = "auto.http.otel.fastify"; | ||
| const HOOK_OP = "hook.fastify"; | ||
| const REQUEST_HANDLER_OP = "request_handler.fastify"; | ||
| const FASTIFY_HOOKS = [ | ||
| "onRequest", | ||
| "preParsing", | ||
| "preValidation", | ||
| "preHandler", | ||
| "preSerialization", | ||
| "onSend", | ||
| "onResponse", | ||
| "onError" | ||
| ]; | ||
| const ATTRIBUTE_HOOK_NAME = "hook.name"; | ||
| const ATTRIBUTE_FASTIFY_TYPE = "fastify.type"; | ||
| const ATTRIBUTE_HOOK_CALLBACK_NAME = "hook.callback.name"; | ||
| const ATTRIBUTE_FASTIFY_ROOT = "fastify.root"; | ||
| const HOOK_TYPE_ROUTE = "route-hook"; | ||
| const HOOK_TYPE_INSTANCE = "hook"; | ||
| const HOOK_TYPE_HANDLER = "request-handler"; | ||
| const ANONYMOUS_FUNCTION_NAME = "anonymous"; | ||
| const kRequestSpan = /* @__PURE__ */ Symbol("sentry fastify request span"); | ||
| const kAddHookOriginal = /* @__PURE__ */ Symbol("sentry fastify addHook original"); | ||
| const kSetNotFoundOriginal = /* @__PURE__ */ Symbol("sentry fastify setNotFoundHandler original"); | ||
| function getRequestRouteUrl(request) { | ||
| return request.routeOptions?.url ?? request.routerPath; | ||
| } | ||
| function getRequestRouteConfig(request) { | ||
| return request.routeOptions?.config ?? request.routeConfig; | ||
| } | ||
| function isFastifyRequest(arg) { | ||
| return !!arg && typeof arg === "object" && !!arg.method && !!arg.url && (!!arg.routeOptions || "routerPath" in arg); | ||
| } | ||
| function fastifyOtelPlugin(instance, _opts, done) { | ||
| instance.decorate(kAddHookOriginal, instance.addHook); | ||
| instance.decorate(kSetNotFoundOriginal, instance.setNotFoundHandler); | ||
| instance.decorateRequest("opentelemetry", function opentelemetry() { | ||
| return { span: this[kRequestSpan] }; | ||
| }); | ||
| instance.decorateRequest(kRequestSpan, null); | ||
| instance.addHook("onRoute", otelWireRoute); | ||
| instance.addHook("onRequest", startRequestSpanHook); | ||
| instance.addHook("onResponse", finalizeNotFoundSpanHook); | ||
| instance.addHook = addHookPatched; | ||
| instance.setNotFoundHandler = setNotFoundHandlerPatched; | ||
| done(); | ||
| } | ||
| const pluginSymbols = fastifyOtelPlugin; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("skip-override")] = true; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("fastify.display-name")] = PACKAGE_NAME; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("plugin-meta")] = { | ||
| fastify: SUPPORTED_VERSIONS, | ||
| name: PACKAGE_NAME | ||
| }; | ||
| function otelWireRoute(routeOptions) { | ||
| if (routeOptions.config?.otel === false) { | ||
| return; | ||
| } | ||
| for (const hook of FASTIFY_HOOKS) { | ||
| const handlerLike = routeOptions[hook]; | ||
| if (typeof handlerLike === "function") { | ||
| routeOptions[hook] = handlerWrapper( | ||
| handlerLike, | ||
| hook, | ||
| routeHookAttributes(this.pluginName, hook, handlerLike, routeOptions.url) | ||
| ); | ||
| } else if (Array.isArray(handlerLike)) { | ||
| routeOptions[hook] = handlerLike.map( | ||
| (handler) => handlerWrapper(handler, hook, routeHookAttributes(this.pluginName, hook, handler, routeOptions.url)) | ||
| ); | ||
| } | ||
| } | ||
| routeOptions.onSend = appendRouteHook(routeOptions.onSend, finalizeResponseSpanHook); | ||
| routeOptions.onError = appendRouteHook(routeOptions.onError, recordErrorInSpanHook); | ||
| routeOptions.handler = handlerWrapper(routeOptions.handler, "handler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - route-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_HANDLER, | ||
| [attributes.HTTP_ROUTE]: routeOptions.url, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: routeOptions.handler.name.length > 0 ? routeOptions.handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| function routeHookAttributes(pluginName, hook, handler, url) { | ||
| return { | ||
| [ATTRIBUTE_HOOK_NAME]: `${pluginName} - route -> ${hook}`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_ROUTE, | ||
| [attributes.HTTP_ROUTE]: url, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }; | ||
| } | ||
| function appendRouteHook(existing, hook) { | ||
| if (existing == null) { | ||
| return hook; | ||
| } | ||
| return Array.isArray(existing) ? [...existing, hook] : [existing, hook]; | ||
| } | ||
| function startRequestSpanHook(request, _reply, hookDone) { | ||
| if (getRequestRouteConfig(request)?.otel === false) { | ||
| return hookDone(); | ||
| } | ||
| const attributes$1 = { | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [ATTRIBUTE_FASTIFY_ROOT]: PACKAGE_NAME, | ||
| [attributes.HTTP_REQUEST_METHOD]: request.method, | ||
| [attributes.URL_PATH]: request.url | ||
| }; | ||
| const route = getRequestRouteUrl(request); | ||
| if (route != null) { | ||
| attributes$1[attributes.HTTP_ROUTE] = route; | ||
| const activeSpan = core.getActiveSpan(); | ||
| const rootSpan = activeSpan && core.getRootSpan(activeSpan); | ||
| if (rootSpan && core.spanToJSON(rootSpan).data[core.SEMANTIC_ATTRIBUTE_SENTRY_OP] === "http.server") { | ||
| rootSpan.setAttribute(attributes.HTTP_ROUTE, route); | ||
| } | ||
| } | ||
| const requestSpan = core.startInactiveSpan({ name: "request", op: REQUEST_HANDLER_OP, attributes: attributes$1 }); | ||
| request[kRequestSpan] = requestSpan; | ||
| core.withActiveSpan(requestSpan, () => { | ||
| hookDone(); | ||
| }); | ||
| } | ||
| function finalizeNotFoundSpanHook(request, reply, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| span.setAttributes({ [attributes.HTTP_RESPONSE_STATUS_CODE]: reply.statusCode }); | ||
| span.end(); | ||
| } | ||
| request[kRequestSpan] = null; | ||
| hookDone(); | ||
| } | ||
| function finalizeResponseSpanHook(request, reply, payload, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| if (reply.statusCode >= 500) { | ||
| span.setStatus({ code: core.SPAN_STATUS_ERROR }); | ||
| } | ||
| span.setAttributes({ [attributes.HTTP_RESPONSE_STATUS_CODE]: reply.statusCode }); | ||
| span.end(); | ||
| } | ||
| request[kRequestSpan] = null; | ||
| hookDone(null, payload); | ||
| } | ||
| function recordErrorInSpanHook(request, _reply, error, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| span.setStatus({ code: core.SPAN_STATUS_ERROR, message: error.message }); | ||
| } | ||
| hookDone(); | ||
| } | ||
| function addHookPatched(name, hook) { | ||
| const addHookOriginal = this[kAddHookOriginal]; | ||
| if (FASTIFY_HOOKS.includes(name)) { | ||
| return addHookOriginal.call( | ||
| this, | ||
| name, | ||
| handlerWrapper(hook, name, { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - ${name}`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hook.name?.length > 0 ? hook.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| } | ||
| return addHookOriginal.call(this, name, hook); | ||
| } | ||
| function setNotFoundHandlerPatched(hooks, handler) { | ||
| const setNotFoundHandlerOriginal = this[kSetNotFoundOriginal]; | ||
| if (typeof hooks === "function") { | ||
| setNotFoundHandlerOriginal.call( | ||
| this, | ||
| handlerWrapper(hooks, "notFoundHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.name?.length > 0 ? hooks.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| return; | ||
| } | ||
| if (hooks.preValidation != null) { | ||
| hooks.preValidation = handlerWrapper(hooks.preValidation, "notFoundHandler - preValidation", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preValidation`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.preValidation.name?.length > 0 ? hooks.preValidation.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| if (hooks.preHandler != null) { | ||
| hooks.preHandler = handlerWrapper(hooks.preHandler, "notFoundHandler - preHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preHandler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.preHandler.name?.length > 0 ? hooks.preHandler.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| if (handler == null) { | ||
| setNotFoundHandlerOriginal.call(this, hooks); | ||
| return; | ||
| } | ||
| setNotFoundHandlerOriginal.call( | ||
| this, | ||
| hooks, | ||
| handlerWrapper(handler, "notFoundHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| } | ||
| function getRequestFromArgs(args) { | ||
| for (const arg of args) { | ||
| if (isFastifyRequest(arg)) { | ||
| return arg; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function handlerWrapper(handler, hookName, spanAttributes = {}) { | ||
| return function handlerWrapped(...args) { | ||
| const request = getRequestFromArgs(args); | ||
| if (request === null || getRequestRouteConfig(request)?.otel === false) { | ||
| return handler.call(this, ...args); | ||
| } | ||
| const parentSpan = request[kRequestSpan] ?? void 0; | ||
| const handlerName = handler.name?.length > 0 ? handler.name : this.pluginName ?? ANONYMOUS_FUNCTION_NAME; | ||
| const hookType = spanAttributes[ATTRIBUTE_FASTIFY_TYPE]; | ||
| const op = hookType === HOOK_TYPE_INSTANCE ? HOOK_OP : hookType === HOOK_TYPE_HANDLER ? REQUEST_HANDLER_OP : void 0; | ||
| const name = op ? stripFastifyPrefix(spanAttributes[ATTRIBUTE_HOOK_NAME]) : `${hookName} - ${handlerName}`; | ||
| return core.startSpan( | ||
| { | ||
| name, | ||
| op, | ||
| attributes: { | ||
| ...spanAttributes, | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN | ||
| }, | ||
| parentSpan | ||
| }, | ||
| () => handler.call(this, ...args) | ||
| ); | ||
| }; | ||
| } | ||
| function stripFastifyPrefix(hookName = "") { | ||
| return hookName.replace(/^fastify -> /, "").replace(/^@fastify\/otel -> /, "").replace(/^@sentry\/instrumentation-fastify -> /, ""); | ||
| } | ||
| function instrumentOnRequest(fastify) { | ||
| fastify.addHook("onRequest", async (request, _reply) => { | ||
| const routeName = getRequestRouteUrl(request); | ||
| const method = request.method || "GET"; | ||
| core.getIsolationScope().setTransactionName(`${method} ${routeName}`); | ||
| }); | ||
| } | ||
| let _isInstrumented = false; | ||
| const instrumentFastify = Object.assign( | ||
| function instrumentFastify2() { | ||
| if (_isInstrumented) { | ||
| return; | ||
| } | ||
| _isInstrumented = true; | ||
| diagnosticsChannel.subscribe("fastify.initialization", (message) => { | ||
| const fastifyInstance = message.fastify; | ||
| fastifyInstance?.register(fastifyOtelPlugin).after((err) => { | ||
| if (err) { | ||
| debugBuild.DEBUG_BUILD && core.debug.error("Failed to setup Fastify instrumentation", err); | ||
| } else if (fastifyInstance) { | ||
| instrumentOnRequest(fastifyInstance); | ||
| } | ||
| }); | ||
| }); | ||
| }, | ||
| { id: "Fastify.v5" } | ||
| ); | ||
| exports.instrumentFastify = instrumentFastify; | ||
| //# sourceMappingURL=instrumentation.js.map |
| {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing-channel/fastify/instrumentation.ts"],"sourcesContent":["/*\n * Copyright (c) 2024-present The Fastify team <https://github.com/fastify/fastify#team>\n * SPDX-License-Identifier: MIT\n *\n * NOTICE from the Sentry authors:\n * - Based on: https://github.com/fastify/otel/tree/bae80d6caef4287e7f01ff3c8dc753243706ea86 (@fastify/otel@0.18.1)\n * - Streamlined to the Sentry SDK's needs: dropped the `InstrumentationBase` wrapper, the unused\n * request/lifecycle hooks, `ignorePaths`/`minimatch` support and the OpenTelemetry tracer/context\n * APIs in favor of the Sentry span API.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-this-alias */\n/* eslint-disable max-lines */\n\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, HTTP_ROUTE, URL_PATH } from '@sentry/conventions/attributes';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n spanToJSON,\n startInactiveSpan,\n startSpan,\n withActiveSpan,\n} from '@sentry/core';\nimport type { FastifyInstance, FastifyRequest } from './types';\nimport { DEBUG_BUILD } from '../../../debug-build';\n\nconst PACKAGE_NAME = '@sentry/instrumentation-fastify';\nconst SUPPORTED_VERSIONS = '>=3.21.0 <6';\n\nconst ORIGIN = 'auto.http.otel.fastify';\nconst HOOK_OP = 'hook.fastify';\nconst REQUEST_HANDLER_OP = 'request_handler.fastify';\n\nconst FASTIFY_HOOKS = [\n 'onRequest',\n 'preParsing',\n 'preValidation',\n 'preHandler',\n 'preSerialization',\n 'onSend',\n 'onResponse',\n 'onError',\n];\nconst ATTRIBUTE_HOOK_NAME = 'hook.name' as const;\nconst ATTRIBUTE_FASTIFY_TYPE = 'fastify.type' as const;\nconst ATTRIBUTE_HOOK_CALLBACK_NAME = 'hook.callback.name' as const;\nconst ATTRIBUTE_FASTIFY_ROOT = 'fastify.root' as const;\n\nconst HOOK_TYPE_ROUTE = 'route-hook' as const;\nconst HOOK_TYPE_INSTANCE = 'hook' as const;\nconst HOOK_TYPE_HANDLER = 'request-handler' as const;\nconst ANONYMOUS_FUNCTION_NAME = 'anonymous';\n\nconst kRequestSpan = Symbol('sentry fastify request span');\nconst kAddHookOriginal = Symbol('sentry fastify addHook original');\nconst kSetNotFoundOriginal = Symbol('sentry fastify setNotFoundHandler original');\n\ntype AnyFn = (...args: any[]) => any;\n\n/**\n * Read the matched route URL off a request. Fastify >=4 exposes it on `request.routeOptions.url`,\n * while v3 only has the (since-removed-in-v5) `request.routerPath`.\n */\nfunction getRequestRouteUrl(request: any): string | undefined {\n return request.routeOptions?.url ?? request.routerPath;\n}\n\n/**\n * Read the per-route config off a request. Fastify >=4 exposes it on `request.routeOptions.config`,\n * while v3 uses `request.routeConfig`. Used to honor the `{ config: { otel: false } }` opt-out.\n */\nfunction getRequestRouteConfig(request: any): { otel?: boolean } | undefined {\n return request.routeOptions?.config ?? request.routeConfig;\n}\n\n/**\n * Detect whether one of a wrapped handler's arguments is the Fastify request. We can't rely on a\n * single property since the route metadata moved from `routerPath` (v3) to `routeOptions` (>=4),\n * so we accept either shape.\n */\nfunction isFastifyRequest(arg: any): boolean {\n return !!arg && typeof arg === 'object' && !!arg.method && !!arg.url && (!!arg.routeOptions || 'routerPath' in arg);\n}\n\n/**\n * The Fastify plugin that wires up the request/hook/handler spans. It is registered on every Fastify\n * instance via the `fastify.initialization` diagnostics channel.\n */\nfunction fastifyOtelPlugin(this: unknown, instance: any, _opts: unknown, done: () => void): void {\n instance.decorate(kAddHookOriginal, instance.addHook);\n instance.decorate(kSetNotFoundOriginal, instance.setNotFoundHandler);\n instance.decorateRequest('opentelemetry', function opentelemetry(this: any) {\n return { span: this[kRequestSpan] as Span | null };\n });\n instance.decorateRequest(kRequestSpan, null);\n\n instance.addHook('onRoute', otelWireRoute);\n instance.addHook('onRequest', startRequestSpanHook);\n instance.addHook('onResponse', finalizeNotFoundSpanHook);\n\n instance.addHook = addHookPatched;\n instance.setNotFoundHandler = setNotFoundHandlerPatched;\n\n done();\n}\n\nconst pluginSymbols = fastifyOtelPlugin as unknown as Record<symbol, unknown>;\npluginSymbols[Symbol.for('skip-override')] = true;\npluginSymbols[Symbol.for('fastify.display-name')] = PACKAGE_NAME;\npluginSymbols[Symbol.for('plugin-meta')] = {\n fastify: SUPPORTED_VERSIONS,\n name: PACKAGE_NAME,\n};\n\nfunction otelWireRoute(this: any, routeOptions: any): void {\n if (routeOptions.config?.otel === false) {\n return;\n }\n\n for (const hook of FASTIFY_HOOKS) {\n const handlerLike = routeOptions[hook];\n\n if (typeof handlerLike === 'function') {\n routeOptions[hook] = handlerWrapper(\n handlerLike,\n hook,\n routeHookAttributes(this.pluginName, hook, handlerLike, routeOptions.url),\n );\n } else if (Array.isArray(handlerLike)) {\n routeOptions[hook] = handlerLike.map((handler: AnyFn) =>\n handlerWrapper(handler, hook, routeHookAttributes(this.pluginName, hook, handler, routeOptions.url)),\n );\n }\n }\n\n routeOptions.onSend = appendRouteHook(routeOptions.onSend, finalizeResponseSpanHook);\n routeOptions.onError = appendRouteHook(routeOptions.onError, recordErrorInSpanHook);\n\n routeOptions.handler = handlerWrapper(routeOptions.handler, 'handler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - route-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_HANDLER,\n [HTTP_ROUTE]: routeOptions.url,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n routeOptions.handler.name.length > 0 ? routeOptions.handler.name : ANONYMOUS_FUNCTION_NAME,\n });\n}\n\nfunction routeHookAttributes(pluginName: string, hook: string, handler: AnyFn, url: string): Record<string, string> {\n return {\n [ATTRIBUTE_HOOK_NAME]: `${pluginName} - route -> ${hook}`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_ROUTE,\n [HTTP_ROUTE]: url,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME,\n };\n}\n\nfunction appendRouteHook(existing: AnyFn | AnyFn[] | undefined, hook: AnyFn): AnyFn | AnyFn[] {\n if (existing == null) {\n return hook;\n }\n return Array.isArray(existing) ? [...existing, hook] : [existing, hook];\n}\n\nfunction startRequestSpanHook(this: any, request: any, _reply: any, hookDone: () => void): void {\n if (getRequestRouteConfig(request)?.otel === false) {\n return hookDone();\n }\n\n const attributes: Record<string, string> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [ATTRIBUTE_FASTIFY_ROOT]: PACKAGE_NAME,\n [HTTP_REQUEST_METHOD]: request.method,\n [URL_PATH]: request.url,\n };\n\n const route = getRequestRouteUrl(request);\n if (route != null) {\n attributes[HTTP_ROUTE] = route;\n\n // Update the route of the request on the root span, if it is a http.server span\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (rootSpan && spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'http.server') {\n rootSpan.setAttribute(HTTP_ROUTE, route);\n }\n }\n\n const requestSpan = startInactiveSpan({ name: 'request', op: REQUEST_HANDLER_OP, attributes });\n request[kRequestSpan] = requestSpan;\n\n // Set the request span as the active span for the remainder of the request lifecycle, so that\n // downstream hooks/handlers as well as errors captured via the error diagnostics channel are\n // parented to it (otherwise they would attach to the root `http.server` span instead).\n withActiveSpan(requestSpan, () => {\n hookDone();\n });\n}\n\nfunction finalizeNotFoundSpanHook(request: any, reply: any, hookDone: () => void): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode });\n span.end();\n }\n\n request[kRequestSpan] = null;\n\n hookDone();\n}\n\nfunction finalizeResponseSpanHook(\n request: any,\n reply: any,\n payload: any,\n hookDone: (err: null, payload: any) => void,\n): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n if (reply.statusCode >= 500) {\n span.setStatus({ code: SPAN_STATUS_ERROR });\n }\n span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode });\n span.end();\n }\n\n request[kRequestSpan] = null;\n\n hookDone(null, payload);\n}\n\nfunction recordErrorInSpanHook(request: any, _reply: any, error: any, hookDone: () => void): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: error.message });\n }\n\n hookDone();\n}\n\nfunction addHookPatched(this: any, name: string, hook: AnyFn): unknown {\n const addHookOriginal = this[kAddHookOriginal];\n\n if (FASTIFY_HOOKS.includes(name)) {\n return addHookOriginal.call(\n this,\n name,\n handlerWrapper(hook, name, {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - ${name}`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: hook.name?.length > 0 ? hook.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n }\n\n return addHookOriginal.call(this, name, hook);\n}\n\nfunction setNotFoundHandlerPatched(this: any, hooks: any, handler?: any): void {\n const setNotFoundHandlerOriginal = this[kSetNotFoundOriginal];\n\n if (typeof hooks === 'function') {\n setNotFoundHandlerOriginal.call(\n this,\n handlerWrapper(hooks, 'notFoundHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.name?.length > 0 ? hooks.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n return;\n }\n\n if (hooks.preValidation != null) {\n hooks.preValidation = handlerWrapper(hooks.preValidation, 'notFoundHandler - preValidation', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preValidation`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n hooks.preValidation.name?.length > 0 ? hooks.preValidation.name : ANONYMOUS_FUNCTION_NAME,\n });\n }\n\n if (hooks.preHandler != null) {\n hooks.preHandler = handlerWrapper(hooks.preHandler, 'notFoundHandler - preHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preHandler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n hooks.preHandler.name?.length > 0 ? hooks.preHandler.name : ANONYMOUS_FUNCTION_NAME,\n });\n }\n\n // Fastify allows `setNotFoundHandler(opts)` without a handler, falling back to its built-in 404\n // handler. Forward the (already-wrapped) hooks unchanged so that fallback still applies.\n if (handler == null) {\n setNotFoundHandlerOriginal.call(this, hooks);\n return;\n }\n\n setNotFoundHandlerOriginal.call(\n this,\n hooks,\n handlerWrapper(handler, 'notFoundHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n}\n\nfunction getRequestFromArgs(args: any[]): any | null {\n for (const arg of args) {\n if (isFastifyRequest(arg)) {\n return arg;\n }\n }\n return null;\n}\n\nfunction handlerWrapper(handler: AnyFn, hookName: string, spanAttributes: Record<string, string> = {}): AnyFn {\n return function handlerWrapped(this: any, ...args: any[]) {\n const request = getRequestFromArgs(args);\n\n if (request === null || getRequestRouteConfig(request)?.otel === false) {\n return handler.call(this, ...args);\n }\n\n const parentSpan = (request[kRequestSpan] as Span | null) ?? undefined;\n const handlerName = handler.name?.length > 0 ? handler.name : (this.pluginName ?? ANONYMOUS_FUNCTION_NAME);\n\n const hookType = spanAttributes[ATTRIBUTE_FASTIFY_TYPE];\n const op =\n hookType === HOOK_TYPE_INSTANCE ? HOOK_OP : hookType === HOOK_TYPE_HANDLER ? REQUEST_HANDLER_OP : undefined;\n\n const name = op ? stripFastifyPrefix(spanAttributes[ATTRIBUTE_HOOK_NAME]) : `${hookName} - ${handlerName}`;\n\n return startSpan(\n {\n name,\n op,\n attributes: {\n ...spanAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n parentSpan,\n },\n () => handler.call(this, ...args),\n );\n };\n}\n\n/**\n * Strip the framework/plugin prefixes from a Fastify `hook.name` to derive a readable span name.\n * This is a bit of a hack and does not always work for all spans, but it's the best we can do without a proper API.\n */\nfunction stripFastifyPrefix(hookName = ''): string {\n return hookName\n .replace(/^fastify -> /, '')\n .replace(/^@fastify\\/otel -> /, '')\n .replace(/^@sentry\\/instrumentation-fastify -> /, '');\n}\n\nfunction instrumentOnRequest(fastify: FastifyInstance): void {\n fastify.addHook('onRequest', async (request: FastifyRequest, _reply) => {\n const routeName = getRequestRouteUrl(request);\n const method = request.method || 'GET';\n\n getIsolationScope().setTransactionName(`${method} ${routeName}`);\n });\n}\n\nlet _isInstrumented = false;\n\n/**\n * Set up the Fastify (>= 3.21.0 < 6) instrumentation by subscribing to the `fastify.initialization`\n * diagnostics channel and registering the span-creating plugin on every Fastify instance.\n *\n * Idempotent and exposes an `id` so it can participate in the OpenTelemetry preload list.\n */\nexport const instrumentFastify = Object.assign(\n function instrumentFastify(): void {\n if (_isInstrumented) {\n return;\n }\n _isInstrumented = true;\n\n diagnosticsChannel.subscribe('fastify.initialization', message => {\n const fastifyInstance = (message as { fastify?: FastifyInstance }).fastify;\n\n fastifyInstance?.register(fastifyOtelPlugin).after(err => {\n if (err) {\n DEBUG_BUILD && debug.error('Failed to setup Fastify instrumentation', err);\n } else if (fastifyInstance) {\n instrumentOnRequest(fastifyInstance);\n }\n });\n });\n },\n { id: 'Fastify.v5' },\n);\n"],"names":["HTTP_ROUTE","attributes","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","HTTP_REQUEST_METHOD","URL_PATH","getActiveSpan","getRootSpan","spanToJSON","SEMANTIC_ATTRIBUTE_SENTRY_OP","startInactiveSpan","withActiveSpan","HTTP_RESPONSE_STATUS_CODE","SPAN_STATUS_ERROR","startSpan","getIsolationScope","instrumentFastify","DEBUG_BUILD","debug"],"mappings":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const INTEGRATION_NAME = "Fastify"; | ||
| function defaultShouldHandleError(_error, _request, reply) { | ||
| const statusCode = reply.statusCode; | ||
| return statusCode >= 500 || statusCode <= 299; | ||
| } | ||
| exports.INTEGRATION_NAME = INTEGRATION_NAME; | ||
| exports.defaultShouldHandleError = defaultShouldHandleError; | ||
| //# sourceMappingURL=utils.js.map |
| {"version":3,"file":"utils.js","sources":["../../../../../src/integrations/tracing-channel/fastify/utils.ts"],"sourcesContent":["import type { FastifyReply, FastifyRequest } from './types';\n\nexport const INTEGRATION_NAME = 'Fastify';\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nexport function defaultShouldHandleError(_error: Error, _request: FastifyRequest, reply: FastifyReply): boolean {\n const statusCode = reply.statusCode;\n // 3xx and 4xx errors are not sent by default.\n return statusCode >= 500 || statusCode <= 299;\n}\n"],"names":[],"mappings":";;AAEO,MAAM,gBAAA,GAAmB;AAOzB,SAAS,wBAAA,CAAyB,MAAA,EAAe,QAAA,EAA0B,KAAA,EAA8B;AAC9G,EAAA,MAAM,aAAa,KAAA,CAAM,UAAA;AAEzB,EAAA,OAAO,UAAA,IAAc,OAAO,UAAA,IAAc,GAAA;AAC5C;;;;;"} |
| 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 = "LruMemoizer"; | ||
| const _lruMemoizerChannelIntegration = (() => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:lru-memoizer] subscribing to channel "${channels.CHANNELS.LRU_MEMOIZER_LOAD}"`); | ||
| core.waitForTracingChannelBinding(() => { | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channels.CHANNELS.LRU_MEMOIZER_LOAD), | ||
| // We only want the helper's caller-context restore for the callback lru-memoizer fires from a detached `setImmediate`. | ||
| () => void 0 | ||
| ); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const lruMemoizerChannelIntegration = core.defineIntegration(_lruMemoizerChannelIntegration); | ||
| exports.lruMemoizerChannelIntegration = lruMemoizerChannelIntegration; | ||
| //# sourceMappingURL=lru-memoizer.js.map |
| {"version":3,"file":"lru-memoizer.js","sources":["../../../../src/integrations/tracing-channel/lru-memoizer.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration, waitForTracingChannelBinding } 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\n// 'LruMemoizer' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'LruMemoizer' as const;\n\ninterface LruMemoizerLoadContext {\n arguments: unknown[];\n}\n\nconst _lruMemoizerChannelIntegration = (() => {\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:lru-memoizer] subscribing to channel \"${CHANNELS.LRU_MEMOIZER_LOAD}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<LruMemoizerLoadContext>(CHANNELS.LRU_MEMOIZER_LOAD),\n // We only want the helper's caller-context restore for the callback lru-memoizer fires from a detached `setImmediate`.\n () => undefined,\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * EXPERIMENTAL — orchestrion-driven lru-memoizer integration. Subscribes to\n * `orchestrion:lru-memoizer:load` (injected into `lru-memoizer/lib/async.js`'s\n * `memoizedFunction`). Creates no spans; only re-runs the memoized callback with the\n * caller's scope. Requires the orchestrion runtime hook or bundler plugin.\n */\nexport const lruMemoizerChannelIntegration = defineIntegration(_lruMemoizerChannelIntegration);\n"],"names":["DEBUG_BUILD","debug","CHANNELS","waitForTracingChannelBinding","bindTracingChannelToSpan","defineIntegration"],"mappings":";;;;;;;;AASA,MAAM,gBAAA,GAAmB,aAAA;AAMzB,MAAM,kCAAkC,MAAM;AAC5C,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,mDAAA,EAAsDC,iBAAA,CAAS,iBAAiB,CAAA,CAAA,CAAG,CAAA;AAE5G,MAAAC,iCAAA,CAA6B,MAAM;AACjC,QAAAC,uCAAA;AAAA,UACE,kBAAA,CAAmB,cAAA,CAAuCF,iBAAA,CAAS,iBAAiB,CAAA;AAAA;AAAA,UAEpF,MAAM;AAAA,SACR;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAQO,MAAM,6BAAA,GAAgCG,uBAAkB,8BAA8B;;;;"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { DEBUG_BUILD } from '../../../debug-build.js'; | ||
| import { debug, captureException, getClient } from '@sentry/core'; | ||
| import { defaultShouldHandleError, INTEGRATION_NAME } from './utils.js'; | ||
| function getFastifyIntegration() { | ||
| const client = getClient(); | ||
| return client?.getIntegrationByName(INTEGRATION_NAME); | ||
| } | ||
| function subscribeToFastifyErrorChannel() { | ||
| diagnosticsChannel.subscribe("tracing:fastify.request.handler:error", (message) => { | ||
| const { error, request, reply } = message; | ||
| handleFastifyError.call(handleFastifyError, error, request, reply, "diagnostics-channel"); | ||
| }); | ||
| } | ||
| function handleFastifyError(error, request, reply, handlerOrigin) { | ||
| const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || defaultShouldHandleError; | ||
| if (handlerOrigin === "diagnostics-channel") { | ||
| this.diagnosticsChannelExists = true; | ||
| } | ||
| if (this.diagnosticsChannelExists && handlerOrigin === "onError-hook") { | ||
| DEBUG_BUILD && debug.warn( | ||
| "Fastify error handler was already registered via diagnostics channel.", | ||
| "You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options." | ||
| ); | ||
| return; | ||
| } | ||
| if (shouldHandleError(error, request, reply)) { | ||
| captureException(error, { | ||
| mechanism: { | ||
| handled: false, | ||
| type: "auto.function.fastify" | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| export { handleFastifyError, subscribeToFastifyErrorChannel }; | ||
| //# sourceMappingURL=errors.js.map |
| {"version":3,"file":"errors.js","sources":["../../../../../src/integrations/tracing-channel/fastify/errors.ts"],"sourcesContent":["import type { FastifyIntegration, FastifyReply, FastifyRequest } from './types';\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { DEBUG_BUILD } from '../../../debug-build';\nimport { getClient, debug, captureException } from '@sentry/core';\nimport { defaultShouldHandleError, INTEGRATION_NAME } from './utils';\n\nfunction getFastifyIntegration(): FastifyIntegration | undefined {\n const client = getClient();\n return client?.getIntegrationByName(INTEGRATION_NAME);\n}\n\n/**\n * Subscribe to the Fastify v5 error diagnostics channel.\n */\nexport function subscribeToFastifyErrorChannel(): void {\n diagnosticsChannel.subscribe('tracing:fastify.request.handler:error', message => {\n const { error, request, reply } = message as {\n error: Error;\n request: FastifyRequest;\n reply: FastifyReply;\n };\n\n handleFastifyError.call(handleFastifyError, error, request, reply, 'diagnostics-channel');\n });\n}\n\n/**\n * Handle a Fastify error, and possibly send it to Sentry.\n */\nexport function handleFastifyError(\n this: {\n diagnosticsChannelExists?: boolean;\n },\n error: Error,\n request: FastifyRequest,\n reply: FastifyReply,\n handlerOrigin: 'diagnostics-channel' | 'onError-hook',\n): void {\n const shouldHandleError = getFastifyIntegration()?.getShouldHandleError() || defaultShouldHandleError;\n // Diagnostics channel runs before the onError hook, so we can use it to check if the handler was already registered\n if (handlerOrigin === 'diagnostics-channel') {\n this.diagnosticsChannelExists = true;\n }\n\n if (this.diagnosticsChannelExists && handlerOrigin === 'onError-hook') {\n DEBUG_BUILD &&\n debug.warn(\n 'Fastify error handler was already registered via diagnostics channel.',\n 'You can safely remove `setupFastifyErrorHandler` call and set `shouldHandleError` on the integration options.',\n );\n\n // If the diagnostics channel already exists, we don't need to handle the error again\n return;\n }\n\n if (shouldHandleError(error, request, reply)) {\n captureException(error, {\n mechanism: {\n handled: false,\n type: 'auto.function.fastify',\n },\n });\n }\n}\n"],"names":[],"mappings":";;;;;AAMA,SAAS,qBAAA,GAAwD;AAC/D,EAAA,MAAM,SAAS,SAAA,EAAU;AACzB,EAAA,OAAO,MAAA,EAAQ,qBAAqB,gBAAgB,CAAA;AACtD;AAKO,SAAS,8BAAA,GAAuC;AACrD,EAAA,kBAAA,CAAmB,SAAA,CAAU,yCAAyC,CAAA,OAAA,KAAW;AAC/E,IAAA,MAAM,EAAE,KAAA,EAAO,OAAA,EAAS,KAAA,EAAM,GAAI,OAAA;AAMlC,IAAA,kBAAA,CAAmB,IAAA,CAAK,kBAAA,EAAoB,KAAA,EAAO,OAAA,EAAS,OAAO,qBAAqB,CAAA;AAAA,EAC1F,CAAC,CAAA;AACH;AAKO,SAAS,kBAAA,CAId,KAAA,EACA,OAAA,EACA,KAAA,EACA,aAAA,EACM;AACN,EAAA,MAAM,iBAAA,GAAoB,qBAAA,EAAsB,EAAG,oBAAA,EAAqB,IAAK,wBAAA;AAE7E,EAAA,IAAI,kBAAkB,qBAAA,EAAuB;AAC3C,IAAA,IAAA,CAAK,wBAAA,GAA2B,IAAA;AAAA,EAClC;AAEA,EAAA,IAAI,IAAA,CAAK,wBAAA,IAA4B,aAAA,KAAkB,cAAA,EAAgB;AACrE,IAAA,WAAA,IACE,KAAA,CAAM,IAAA;AAAA,MACJ,uEAAA;AAAA,MACA;AAAA,KACF;AAGF,IAAA;AAAA,EACF;AAEA,EAAA,IAAI,iBAAA,CAAkB,KAAA,EAAO,OAAA,EAAS,KAAK,CAAA,EAAG;AAC5C,IAAA,gBAAA,CAAiB,KAAA,EAAO;AAAA,MACtB,SAAA,EAAW;AAAA,QACT,OAAA,EAAS,KAAA;AAAA,QACT,IAAA,EAAM;AAAA;AACR,KACD,CAAA;AAAA,EACH;AACF;;;;"} |
| import { defineIntegration } from '@sentry/core'; | ||
| import { instrumentFastify as instrumentFastify$1 } from './instrumentation.js'; | ||
| import { INTEGRATION_NAME, defaultShouldHandleError } from './utils.js'; | ||
| import { subscribeToFastifyErrorChannel, handleFastifyError as handleFastifyError$1 } from './errors.js'; | ||
| const _fastifyIntegration = (({ shouldHandleError }) => { | ||
| let _shouldHandleError; | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| _shouldHandleError = shouldHandleError || defaultShouldHandleError; | ||
| subscribeToFastifyErrorChannel(); | ||
| instrumentFastify$1(); | ||
| }, | ||
| getShouldHandleError() { | ||
| return _shouldHandleError; | ||
| }, | ||
| setShouldHandleError(shouldHandleError2) { | ||
| _shouldHandleError = shouldHandleError2; | ||
| } | ||
| }; | ||
| }); | ||
| const fastifyIntegration = defineIntegration( | ||
| (options = {}) => _fastifyIntegration(options) | ||
| ); | ||
| const instrumentFastify = instrumentFastify$1; | ||
| const handleFastifyError = handleFastifyError$1; | ||
| export { fastifyIntegration, handleFastifyError, instrumentFastify }; | ||
| //# sourceMappingURL=index.js.map |
| {"version":3,"file":"index.js","sources":["../../../../../src/integrations/tracing-channel/fastify/index.ts"],"sourcesContent":["import type { IntegrationFn } from '@sentry/core';\nimport { defineIntegration } from '@sentry/core';\nimport type { FastifyIntegration, FastifyReply, FastifyRequest } from './types';\n\nimport { instrumentFastify as _instrumentFastify } from './instrumentation';\nimport { defaultShouldHandleError, INTEGRATION_NAME } from './utils';\nimport { subscribeToFastifyErrorChannel, handleFastifyError as _handleFastifyError } from './errors';\n\n/**\n * Options for the Fastify integration.\n *\n * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @example\n *\n * ```javascript\n * Sentry.init({\n * integrations: [\n * Sentry.fastifyIntegration({\n * shouldHandleError(_error, _request, reply) {\n * return reply.statusCode >= 500;\n * },\n * });\n * },\n * });\n * ```\n *\n */\ninterface FastifyIntegrationOptions {\n /**\n * Callback method deciding whether error should be captured and sent to Sentry\n * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel.\n * Fastify v3 and v4 use `setupFastifyErrorHandler` instead.\n *\n * @param error Captured Fastify error\n * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath)\n * @param reply Fastify reply (or any object containing at least statusCode)\n */\n shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n}\n\nconst _fastifyIntegration = (({ shouldHandleError }: Partial<FastifyIntegrationOptions>) => {\n let _shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean;\n\n return {\n name: INTEGRATION_NAME,\n setupOnce() {\n _shouldHandleError = shouldHandleError || defaultShouldHandleError;\n\n subscribeToFastifyErrorChannel();\n _instrumentFastify();\n },\n getShouldHandleError() {\n return _shouldHandleError;\n },\n setShouldHandleError(shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean) {\n _shouldHandleError = shouldHandleError;\n },\n } satisfies FastifyIntegration;\n}) satisfies IntegrationFn;\n\n/**\n * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/).\n * This integration supports Fastify v5 only.\n *\n * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/).\n *\n * @example\n * ```javascript\n * const Sentry = require('@sentry/node');\n *\n * Sentry.init({\n * integrations: [Sentry.fastifyIntegration()],\n * })\n * ```\n */\nexport const fastifyIntegration = defineIntegration((options: Partial<FastifyIntegrationOptions> = {}) =>\n _fastifyIntegration(options),\n);\n\n/**\n * @deprecated This export is deprecated and will not longer be exposed in the next major version.\n */\nexport const instrumentFastify = _instrumentFastify;\n\n/**\n * @deprecated This export is deprecated and will not longer be exposed in the next major version.\n */\nexport const handleFastifyError = _handleFastifyError;\n"],"names":["_instrumentFastify","shouldHandleError","_handleFastifyError"],"mappings":";;;;;AA2CA,MAAM,mBAAA,IAAuB,CAAC,EAAE,iBAAA,EAAkB,KAA0C;AAC1F,EAAA,IAAI,kBAAA;AAEJ,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AACV,MAAA,kBAAA,GAAqB,iBAAA,IAAqB,wBAAA;AAE1C,MAAA,8BAAA,EAA+B;AAC/B,MAAAA,mBAAA,EAAmB;AAAA,IACrB,CAAA;AAAA,IACA,oBAAA,GAAuB;AACrB,MAAA,OAAO,kBAAA;AAAA,IACT,CAAA;AAAA,IACA,qBAAqBC,kBAAAA,EAA4F;AAC/G,MAAA,kBAAA,GAAqBA,kBAAAA;AAAA,IACvB;AAAA,GACF;AACF,CAAA,CAAA;AAiBO,MAAM,kBAAA,GAAqB,iBAAA;AAAA,EAAkB,CAAC,OAAA,GAA8C,EAAC,KAClG,oBAAoB,OAAO;AAC7B;AAKO,MAAM,iBAAA,GAAoBD;AAK1B,MAAM,kBAAA,GAAqBE;;;;"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { HTTP_ROUTE, URL_PATH, HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE } from '@sentry/conventions/attributes'; | ||
| import { debug, getIsolationScope, getActiveSpan, getRootSpan, spanToJSON, SEMANTIC_ATTRIBUTE_SENTRY_OP, startInactiveSpan, withActiveSpan, startSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from '../../../debug-build.js'; | ||
| const PACKAGE_NAME = "@sentry/instrumentation-fastify"; | ||
| const SUPPORTED_VERSIONS = ">=3.21.0 <6"; | ||
| const ORIGIN = "auto.http.otel.fastify"; | ||
| const HOOK_OP = "hook.fastify"; | ||
| const REQUEST_HANDLER_OP = "request_handler.fastify"; | ||
| const FASTIFY_HOOKS = [ | ||
| "onRequest", | ||
| "preParsing", | ||
| "preValidation", | ||
| "preHandler", | ||
| "preSerialization", | ||
| "onSend", | ||
| "onResponse", | ||
| "onError" | ||
| ]; | ||
| const ATTRIBUTE_HOOK_NAME = "hook.name"; | ||
| const ATTRIBUTE_FASTIFY_TYPE = "fastify.type"; | ||
| const ATTRIBUTE_HOOK_CALLBACK_NAME = "hook.callback.name"; | ||
| const ATTRIBUTE_FASTIFY_ROOT = "fastify.root"; | ||
| const HOOK_TYPE_ROUTE = "route-hook"; | ||
| const HOOK_TYPE_INSTANCE = "hook"; | ||
| const HOOK_TYPE_HANDLER = "request-handler"; | ||
| const ANONYMOUS_FUNCTION_NAME = "anonymous"; | ||
| const kRequestSpan = /* @__PURE__ */ Symbol("sentry fastify request span"); | ||
| const kAddHookOriginal = /* @__PURE__ */ Symbol("sentry fastify addHook original"); | ||
| const kSetNotFoundOriginal = /* @__PURE__ */ Symbol("sentry fastify setNotFoundHandler original"); | ||
| function getRequestRouteUrl(request) { | ||
| return request.routeOptions?.url ?? request.routerPath; | ||
| } | ||
| function getRequestRouteConfig(request) { | ||
| return request.routeOptions?.config ?? request.routeConfig; | ||
| } | ||
| function isFastifyRequest(arg) { | ||
| return !!arg && typeof arg === "object" && !!arg.method && !!arg.url && (!!arg.routeOptions || "routerPath" in arg); | ||
| } | ||
| function fastifyOtelPlugin(instance, _opts, done) { | ||
| instance.decorate(kAddHookOriginal, instance.addHook); | ||
| instance.decorate(kSetNotFoundOriginal, instance.setNotFoundHandler); | ||
| instance.decorateRequest("opentelemetry", function opentelemetry() { | ||
| return { span: this[kRequestSpan] }; | ||
| }); | ||
| instance.decorateRequest(kRequestSpan, null); | ||
| instance.addHook("onRoute", otelWireRoute); | ||
| instance.addHook("onRequest", startRequestSpanHook); | ||
| instance.addHook("onResponse", finalizeNotFoundSpanHook); | ||
| instance.addHook = addHookPatched; | ||
| instance.setNotFoundHandler = setNotFoundHandlerPatched; | ||
| done(); | ||
| } | ||
| const pluginSymbols = fastifyOtelPlugin; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("skip-override")] = true; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("fastify.display-name")] = PACKAGE_NAME; | ||
| pluginSymbols[/* @__PURE__ */ Symbol.for("plugin-meta")] = { | ||
| fastify: SUPPORTED_VERSIONS, | ||
| name: PACKAGE_NAME | ||
| }; | ||
| function otelWireRoute(routeOptions) { | ||
| if (routeOptions.config?.otel === false) { | ||
| return; | ||
| } | ||
| for (const hook of FASTIFY_HOOKS) { | ||
| const handlerLike = routeOptions[hook]; | ||
| if (typeof handlerLike === "function") { | ||
| routeOptions[hook] = handlerWrapper( | ||
| handlerLike, | ||
| hook, | ||
| routeHookAttributes(this.pluginName, hook, handlerLike, routeOptions.url) | ||
| ); | ||
| } else if (Array.isArray(handlerLike)) { | ||
| routeOptions[hook] = handlerLike.map( | ||
| (handler) => handlerWrapper(handler, hook, routeHookAttributes(this.pluginName, hook, handler, routeOptions.url)) | ||
| ); | ||
| } | ||
| } | ||
| routeOptions.onSend = appendRouteHook(routeOptions.onSend, finalizeResponseSpanHook); | ||
| routeOptions.onError = appendRouteHook(routeOptions.onError, recordErrorInSpanHook); | ||
| routeOptions.handler = handlerWrapper(routeOptions.handler, "handler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - route-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_HANDLER, | ||
| [HTTP_ROUTE]: routeOptions.url, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: routeOptions.handler.name.length > 0 ? routeOptions.handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| function routeHookAttributes(pluginName, hook, handler, url) { | ||
| return { | ||
| [ATTRIBUTE_HOOK_NAME]: `${pluginName} - route -> ${hook}`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_ROUTE, | ||
| [HTTP_ROUTE]: url, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }; | ||
| } | ||
| function appendRouteHook(existing, hook) { | ||
| if (existing == null) { | ||
| return hook; | ||
| } | ||
| return Array.isArray(existing) ? [...existing, hook] : [existing, hook]; | ||
| } | ||
| function startRequestSpanHook(request, _reply, hookDone) { | ||
| if (getRequestRouteConfig(request)?.otel === false) { | ||
| return hookDone(); | ||
| } | ||
| const attributes = { | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN, | ||
| [ATTRIBUTE_FASTIFY_ROOT]: PACKAGE_NAME, | ||
| [HTTP_REQUEST_METHOD]: request.method, | ||
| [URL_PATH]: request.url | ||
| }; | ||
| const route = getRequestRouteUrl(request); | ||
| if (route != null) { | ||
| attributes[HTTP_ROUTE] = route; | ||
| const activeSpan = getActiveSpan(); | ||
| const rootSpan = activeSpan && getRootSpan(activeSpan); | ||
| if (rootSpan && spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] === "http.server") { | ||
| rootSpan.setAttribute(HTTP_ROUTE, route); | ||
| } | ||
| } | ||
| const requestSpan = startInactiveSpan({ name: "request", op: REQUEST_HANDLER_OP, attributes }); | ||
| request[kRequestSpan] = requestSpan; | ||
| withActiveSpan(requestSpan, () => { | ||
| hookDone(); | ||
| }); | ||
| } | ||
| function finalizeNotFoundSpanHook(request, reply, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode }); | ||
| span.end(); | ||
| } | ||
| request[kRequestSpan] = null; | ||
| hookDone(); | ||
| } | ||
| function finalizeResponseSpanHook(request, reply, payload, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| if (reply.statusCode >= 500) { | ||
| span.setStatus({ code: SPAN_STATUS_ERROR }); | ||
| } | ||
| span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode }); | ||
| span.end(); | ||
| } | ||
| request[kRequestSpan] = null; | ||
| hookDone(null, payload); | ||
| } | ||
| function recordErrorInSpanHook(request, _reply, error, hookDone) { | ||
| const span = request[kRequestSpan]; | ||
| if (span != null) { | ||
| span.setStatus({ code: SPAN_STATUS_ERROR, message: error.message }); | ||
| } | ||
| hookDone(); | ||
| } | ||
| function addHookPatched(name, hook) { | ||
| const addHookOriginal = this[kAddHookOriginal]; | ||
| if (FASTIFY_HOOKS.includes(name)) { | ||
| return addHookOriginal.call( | ||
| this, | ||
| name, | ||
| handlerWrapper(hook, name, { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - ${name}`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hook.name?.length > 0 ? hook.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| } | ||
| return addHookOriginal.call(this, name, hook); | ||
| } | ||
| function setNotFoundHandlerPatched(hooks, handler) { | ||
| const setNotFoundHandlerOriginal = this[kSetNotFoundOriginal]; | ||
| if (typeof hooks === "function") { | ||
| setNotFoundHandlerOriginal.call( | ||
| this, | ||
| handlerWrapper(hooks, "notFoundHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.name?.length > 0 ? hooks.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| return; | ||
| } | ||
| if (hooks.preValidation != null) { | ||
| hooks.preValidation = handlerWrapper(hooks.preValidation, "notFoundHandler - preValidation", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preValidation`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.preValidation.name?.length > 0 ? hooks.preValidation.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| if (hooks.preHandler != null) { | ||
| hooks.preHandler = handlerWrapper(hooks.preHandler, "notFoundHandler - preHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preHandler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.preHandler.name?.length > 0 ? hooks.preHandler.name : ANONYMOUS_FUNCTION_NAME | ||
| }); | ||
| } | ||
| if (handler == null) { | ||
| setNotFoundHandlerOriginal.call(this, hooks); | ||
| return; | ||
| } | ||
| setNotFoundHandlerOriginal.call( | ||
| this, | ||
| hooks, | ||
| handlerWrapper(handler, "notFoundHandler", { | ||
| [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`, | ||
| [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE, | ||
| [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME | ||
| }) | ||
| ); | ||
| } | ||
| function getRequestFromArgs(args) { | ||
| for (const arg of args) { | ||
| if (isFastifyRequest(arg)) { | ||
| return arg; | ||
| } | ||
| } | ||
| return null; | ||
| } | ||
| function handlerWrapper(handler, hookName, spanAttributes = {}) { | ||
| return function handlerWrapped(...args) { | ||
| const request = getRequestFromArgs(args); | ||
| if (request === null || getRequestRouteConfig(request)?.otel === false) { | ||
| return handler.call(this, ...args); | ||
| } | ||
| const parentSpan = request[kRequestSpan] ?? void 0; | ||
| const handlerName = handler.name?.length > 0 ? handler.name : this.pluginName ?? ANONYMOUS_FUNCTION_NAME; | ||
| const hookType = spanAttributes[ATTRIBUTE_FASTIFY_TYPE]; | ||
| const op = hookType === HOOK_TYPE_INSTANCE ? HOOK_OP : hookType === HOOK_TYPE_HANDLER ? REQUEST_HANDLER_OP : void 0; | ||
| const name = op ? stripFastifyPrefix(spanAttributes[ATTRIBUTE_HOOK_NAME]) : `${hookName} - ${handlerName}`; | ||
| return startSpan( | ||
| { | ||
| name, | ||
| op, | ||
| attributes: { | ||
| ...spanAttributes, | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN | ||
| }, | ||
| parentSpan | ||
| }, | ||
| () => handler.call(this, ...args) | ||
| ); | ||
| }; | ||
| } | ||
| function stripFastifyPrefix(hookName = "") { | ||
| return hookName.replace(/^fastify -> /, "").replace(/^@fastify\/otel -> /, "").replace(/^@sentry\/instrumentation-fastify -> /, ""); | ||
| } | ||
| function instrumentOnRequest(fastify) { | ||
| fastify.addHook("onRequest", async (request, _reply) => { | ||
| const routeName = getRequestRouteUrl(request); | ||
| const method = request.method || "GET"; | ||
| getIsolationScope().setTransactionName(`${method} ${routeName}`); | ||
| }); | ||
| } | ||
| let _isInstrumented = false; | ||
| const instrumentFastify = Object.assign( | ||
| function instrumentFastify2() { | ||
| if (_isInstrumented) { | ||
| return; | ||
| } | ||
| _isInstrumented = true; | ||
| diagnosticsChannel.subscribe("fastify.initialization", (message) => { | ||
| const fastifyInstance = message.fastify; | ||
| fastifyInstance?.register(fastifyOtelPlugin).after((err) => { | ||
| if (err) { | ||
| DEBUG_BUILD && debug.error("Failed to setup Fastify instrumentation", err); | ||
| } else if (fastifyInstance) { | ||
| instrumentOnRequest(fastifyInstance); | ||
| } | ||
| }); | ||
| }); | ||
| }, | ||
| { id: "Fastify.v5" } | ||
| ); | ||
| export { instrumentFastify }; | ||
| //# sourceMappingURL=instrumentation.js.map |
| {"version":3,"file":"instrumentation.js","sources":["../../../../../src/integrations/tracing-channel/fastify/instrumentation.ts"],"sourcesContent":["/*\n * Copyright (c) 2024-present The Fastify team <https://github.com/fastify/fastify#team>\n * SPDX-License-Identifier: MIT\n *\n * NOTICE from the Sentry authors:\n * - Based on: https://github.com/fastify/otel/tree/bae80d6caef4287e7f01ff3c8dc753243706ea86 (@fastify/otel@0.18.1)\n * - Streamlined to the Sentry SDK's needs: dropped the `InstrumentationBase` wrapper, the unused\n * request/lifecycle hooks, `ignorePaths`/`minimatch` support and the OpenTelemetry tracer/context\n * APIs in favor of the Sentry span API.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-unsafe-member-access */\n/* eslint-disable @typescript-eslint/no-this-alias */\n/* eslint-disable max-lines */\n\nimport * as diagnosticsChannel from 'node:diagnostics_channel';\nimport { HTTP_REQUEST_METHOD, HTTP_RESPONSE_STATUS_CODE, HTTP_ROUTE, URL_PATH } from '@sentry/conventions/attributes';\nimport type { Span } from '@sentry/core';\nimport {\n debug,\n getActiveSpan,\n getIsolationScope,\n getRootSpan,\n SEMANTIC_ATTRIBUTE_SENTRY_OP,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n spanToJSON,\n startInactiveSpan,\n startSpan,\n withActiveSpan,\n} from '@sentry/core';\nimport type { FastifyInstance, FastifyRequest } from './types';\nimport { DEBUG_BUILD } from '../../../debug-build';\n\nconst PACKAGE_NAME = '@sentry/instrumentation-fastify';\nconst SUPPORTED_VERSIONS = '>=3.21.0 <6';\n\nconst ORIGIN = 'auto.http.otel.fastify';\nconst HOOK_OP = 'hook.fastify';\nconst REQUEST_HANDLER_OP = 'request_handler.fastify';\n\nconst FASTIFY_HOOKS = [\n 'onRequest',\n 'preParsing',\n 'preValidation',\n 'preHandler',\n 'preSerialization',\n 'onSend',\n 'onResponse',\n 'onError',\n];\nconst ATTRIBUTE_HOOK_NAME = 'hook.name' as const;\nconst ATTRIBUTE_FASTIFY_TYPE = 'fastify.type' as const;\nconst ATTRIBUTE_HOOK_CALLBACK_NAME = 'hook.callback.name' as const;\nconst ATTRIBUTE_FASTIFY_ROOT = 'fastify.root' as const;\n\nconst HOOK_TYPE_ROUTE = 'route-hook' as const;\nconst HOOK_TYPE_INSTANCE = 'hook' as const;\nconst HOOK_TYPE_HANDLER = 'request-handler' as const;\nconst ANONYMOUS_FUNCTION_NAME = 'anonymous';\n\nconst kRequestSpan = Symbol('sentry fastify request span');\nconst kAddHookOriginal = Symbol('sentry fastify addHook original');\nconst kSetNotFoundOriginal = Symbol('sentry fastify setNotFoundHandler original');\n\ntype AnyFn = (...args: any[]) => any;\n\n/**\n * Read the matched route URL off a request. Fastify >=4 exposes it on `request.routeOptions.url`,\n * while v3 only has the (since-removed-in-v5) `request.routerPath`.\n */\nfunction getRequestRouteUrl(request: any): string | undefined {\n return request.routeOptions?.url ?? request.routerPath;\n}\n\n/**\n * Read the per-route config off a request. Fastify >=4 exposes it on `request.routeOptions.config`,\n * while v3 uses `request.routeConfig`. Used to honor the `{ config: { otel: false } }` opt-out.\n */\nfunction getRequestRouteConfig(request: any): { otel?: boolean } | undefined {\n return request.routeOptions?.config ?? request.routeConfig;\n}\n\n/**\n * Detect whether one of a wrapped handler's arguments is the Fastify request. We can't rely on a\n * single property since the route metadata moved from `routerPath` (v3) to `routeOptions` (>=4),\n * so we accept either shape.\n */\nfunction isFastifyRequest(arg: any): boolean {\n return !!arg && typeof arg === 'object' && !!arg.method && !!arg.url && (!!arg.routeOptions || 'routerPath' in arg);\n}\n\n/**\n * The Fastify plugin that wires up the request/hook/handler spans. It is registered on every Fastify\n * instance via the `fastify.initialization` diagnostics channel.\n */\nfunction fastifyOtelPlugin(this: unknown, instance: any, _opts: unknown, done: () => void): void {\n instance.decorate(kAddHookOriginal, instance.addHook);\n instance.decorate(kSetNotFoundOriginal, instance.setNotFoundHandler);\n instance.decorateRequest('opentelemetry', function opentelemetry(this: any) {\n return { span: this[kRequestSpan] as Span | null };\n });\n instance.decorateRequest(kRequestSpan, null);\n\n instance.addHook('onRoute', otelWireRoute);\n instance.addHook('onRequest', startRequestSpanHook);\n instance.addHook('onResponse', finalizeNotFoundSpanHook);\n\n instance.addHook = addHookPatched;\n instance.setNotFoundHandler = setNotFoundHandlerPatched;\n\n done();\n}\n\nconst pluginSymbols = fastifyOtelPlugin as unknown as Record<symbol, unknown>;\npluginSymbols[Symbol.for('skip-override')] = true;\npluginSymbols[Symbol.for('fastify.display-name')] = PACKAGE_NAME;\npluginSymbols[Symbol.for('plugin-meta')] = {\n fastify: SUPPORTED_VERSIONS,\n name: PACKAGE_NAME,\n};\n\nfunction otelWireRoute(this: any, routeOptions: any): void {\n if (routeOptions.config?.otel === false) {\n return;\n }\n\n for (const hook of FASTIFY_HOOKS) {\n const handlerLike = routeOptions[hook];\n\n if (typeof handlerLike === 'function') {\n routeOptions[hook] = handlerWrapper(\n handlerLike,\n hook,\n routeHookAttributes(this.pluginName, hook, handlerLike, routeOptions.url),\n );\n } else if (Array.isArray(handlerLike)) {\n routeOptions[hook] = handlerLike.map((handler: AnyFn) =>\n handlerWrapper(handler, hook, routeHookAttributes(this.pluginName, hook, handler, routeOptions.url)),\n );\n }\n }\n\n routeOptions.onSend = appendRouteHook(routeOptions.onSend, finalizeResponseSpanHook);\n routeOptions.onError = appendRouteHook(routeOptions.onError, recordErrorInSpanHook);\n\n routeOptions.handler = handlerWrapper(routeOptions.handler, 'handler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - route-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_HANDLER,\n [HTTP_ROUTE]: routeOptions.url,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n routeOptions.handler.name.length > 0 ? routeOptions.handler.name : ANONYMOUS_FUNCTION_NAME,\n });\n}\n\nfunction routeHookAttributes(pluginName: string, hook: string, handler: AnyFn, url: string): Record<string, string> {\n return {\n [ATTRIBUTE_HOOK_NAME]: `${pluginName} - route -> ${hook}`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_ROUTE,\n [HTTP_ROUTE]: url,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME,\n };\n}\n\nfunction appendRouteHook(existing: AnyFn | AnyFn[] | undefined, hook: AnyFn): AnyFn | AnyFn[] {\n if (existing == null) {\n return hook;\n }\n return Array.isArray(existing) ? [...existing, hook] : [existing, hook];\n}\n\nfunction startRequestSpanHook(this: any, request: any, _reply: any, hookDone: () => void): void {\n if (getRequestRouteConfig(request)?.otel === false) {\n return hookDone();\n }\n\n const attributes: Record<string, string> = {\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n [ATTRIBUTE_FASTIFY_ROOT]: PACKAGE_NAME,\n [HTTP_REQUEST_METHOD]: request.method,\n [URL_PATH]: request.url,\n };\n\n const route = getRequestRouteUrl(request);\n if (route != null) {\n attributes[HTTP_ROUTE] = route;\n\n // Update the route of the request on the root span, if it is a http.server span\n const activeSpan = getActiveSpan();\n const rootSpan = activeSpan && getRootSpan(activeSpan);\n if (rootSpan && spanToJSON(rootSpan).data[SEMANTIC_ATTRIBUTE_SENTRY_OP] === 'http.server') {\n rootSpan.setAttribute(HTTP_ROUTE, route);\n }\n }\n\n const requestSpan = startInactiveSpan({ name: 'request', op: REQUEST_HANDLER_OP, attributes });\n request[kRequestSpan] = requestSpan;\n\n // Set the request span as the active span for the remainder of the request lifecycle, so that\n // downstream hooks/handlers as well as errors captured via the error diagnostics channel are\n // parented to it (otherwise they would attach to the root `http.server` span instead).\n withActiveSpan(requestSpan, () => {\n hookDone();\n });\n}\n\nfunction finalizeNotFoundSpanHook(request: any, reply: any, hookDone: () => void): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode });\n span.end();\n }\n\n request[kRequestSpan] = null;\n\n hookDone();\n}\n\nfunction finalizeResponseSpanHook(\n request: any,\n reply: any,\n payload: any,\n hookDone: (err: null, payload: any) => void,\n): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n if (reply.statusCode >= 500) {\n span.setStatus({ code: SPAN_STATUS_ERROR });\n }\n span.setAttributes({ [HTTP_RESPONSE_STATUS_CODE]: reply.statusCode });\n span.end();\n }\n\n request[kRequestSpan] = null;\n\n hookDone(null, payload);\n}\n\nfunction recordErrorInSpanHook(request: any, _reply: any, error: any, hookDone: () => void): void {\n const span = request[kRequestSpan] as Span | null;\n\n if (span != null) {\n span.setStatus({ code: SPAN_STATUS_ERROR, message: error.message });\n }\n\n hookDone();\n}\n\nfunction addHookPatched(this: any, name: string, hook: AnyFn): unknown {\n const addHookOriginal = this[kAddHookOriginal];\n\n if (FASTIFY_HOOKS.includes(name)) {\n return addHookOriginal.call(\n this,\n name,\n handlerWrapper(hook, name, {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - ${name}`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: hook.name?.length > 0 ? hook.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n }\n\n return addHookOriginal.call(this, name, hook);\n}\n\nfunction setNotFoundHandlerPatched(this: any, hooks: any, handler?: any): void {\n const setNotFoundHandlerOriginal = this[kSetNotFoundOriginal];\n\n if (typeof hooks === 'function') {\n setNotFoundHandlerOriginal.call(\n this,\n handlerWrapper(hooks, 'notFoundHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: hooks.name?.length > 0 ? hooks.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n return;\n }\n\n if (hooks.preValidation != null) {\n hooks.preValidation = handlerWrapper(hooks.preValidation, 'notFoundHandler - preValidation', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preValidation`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n hooks.preValidation.name?.length > 0 ? hooks.preValidation.name : ANONYMOUS_FUNCTION_NAME,\n });\n }\n\n if (hooks.preHandler != null) {\n hooks.preHandler = handlerWrapper(hooks.preHandler, 'notFoundHandler - preHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler - preHandler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]:\n hooks.preHandler.name?.length > 0 ? hooks.preHandler.name : ANONYMOUS_FUNCTION_NAME,\n });\n }\n\n // Fastify allows `setNotFoundHandler(opts)` without a handler, falling back to its built-in 404\n // handler. Forward the (already-wrapped) hooks unchanged so that fallback still applies.\n if (handler == null) {\n setNotFoundHandlerOriginal.call(this, hooks);\n return;\n }\n\n setNotFoundHandlerOriginal.call(\n this,\n hooks,\n handlerWrapper(handler, 'notFoundHandler', {\n [ATTRIBUTE_HOOK_NAME]: `${this.pluginName} - not-found-handler`,\n [ATTRIBUTE_FASTIFY_TYPE]: HOOK_TYPE_INSTANCE,\n [ATTRIBUTE_HOOK_CALLBACK_NAME]: handler.name?.length > 0 ? handler.name : ANONYMOUS_FUNCTION_NAME,\n }),\n );\n}\n\nfunction getRequestFromArgs(args: any[]): any | null {\n for (const arg of args) {\n if (isFastifyRequest(arg)) {\n return arg;\n }\n }\n return null;\n}\n\nfunction handlerWrapper(handler: AnyFn, hookName: string, spanAttributes: Record<string, string> = {}): AnyFn {\n return function handlerWrapped(this: any, ...args: any[]) {\n const request = getRequestFromArgs(args);\n\n if (request === null || getRequestRouteConfig(request)?.otel === false) {\n return handler.call(this, ...args);\n }\n\n const parentSpan = (request[kRequestSpan] as Span | null) ?? undefined;\n const handlerName = handler.name?.length > 0 ? handler.name : (this.pluginName ?? ANONYMOUS_FUNCTION_NAME);\n\n const hookType = spanAttributes[ATTRIBUTE_FASTIFY_TYPE];\n const op =\n hookType === HOOK_TYPE_INSTANCE ? HOOK_OP : hookType === HOOK_TYPE_HANDLER ? REQUEST_HANDLER_OP : undefined;\n\n const name = op ? stripFastifyPrefix(spanAttributes[ATTRIBUTE_HOOK_NAME]) : `${hookName} - ${handlerName}`;\n\n return startSpan(\n {\n name,\n op,\n attributes: {\n ...spanAttributes,\n [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: ORIGIN,\n },\n parentSpan,\n },\n () => handler.call(this, ...args),\n );\n };\n}\n\n/**\n * Strip the framework/plugin prefixes from a Fastify `hook.name` to derive a readable span name.\n * This is a bit of a hack and does not always work for all spans, but it's the best we can do without a proper API.\n */\nfunction stripFastifyPrefix(hookName = ''): string {\n return hookName\n .replace(/^fastify -> /, '')\n .replace(/^@fastify\\/otel -> /, '')\n .replace(/^@sentry\\/instrumentation-fastify -> /, '');\n}\n\nfunction instrumentOnRequest(fastify: FastifyInstance): void {\n fastify.addHook('onRequest', async (request: FastifyRequest, _reply) => {\n const routeName = getRequestRouteUrl(request);\n const method = request.method || 'GET';\n\n getIsolationScope().setTransactionName(`${method} ${routeName}`);\n });\n}\n\nlet _isInstrumented = false;\n\n/**\n * Set up the Fastify (>= 3.21.0 < 6) instrumentation by subscribing to the `fastify.initialization`\n * diagnostics channel and registering the span-creating plugin on every Fastify instance.\n *\n * Idempotent and exposes an `id` so it can participate in the OpenTelemetry preload list.\n */\nexport const instrumentFastify = Object.assign(\n function instrumentFastify(): void {\n if (_isInstrumented) {\n return;\n }\n _isInstrumented = true;\n\n diagnosticsChannel.subscribe('fastify.initialization', message => {\n const fastifyInstance = (message as { fastify?: FastifyInstance }).fastify;\n\n fastifyInstance?.register(fastifyOtelPlugin).after(err => {\n if (err) {\n DEBUG_BUILD && debug.error('Failed to setup Fastify instrumentation', err);\n } else if (fastifyInstance) {\n instrumentOnRequest(fastifyInstance);\n }\n });\n });\n },\n { id: 'Fastify.v5' },\n);\n"],"names":["instrumentFastify"],"mappings":"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"} |
| const INTEGRATION_NAME = "Fastify"; | ||
| function defaultShouldHandleError(_error, _request, reply) { | ||
| const statusCode = reply.statusCode; | ||
| return statusCode >= 500 || statusCode <= 299; | ||
| } | ||
| export { INTEGRATION_NAME, defaultShouldHandleError }; | ||
| //# sourceMappingURL=utils.js.map |
| {"version":3,"file":"utils.js","sources":["../../../../../src/integrations/tracing-channel/fastify/utils.ts"],"sourcesContent":["import type { FastifyReply, FastifyRequest } from './types';\n\nexport const INTEGRATION_NAME = 'Fastify';\n\n/**\n * Default function to determine if an error should be sent to Sentry\n *\n * 3xx and 4xx errors are not sent by default.\n */\nexport function defaultShouldHandleError(_error: Error, _request: FastifyRequest, reply: FastifyReply): boolean {\n const statusCode = reply.statusCode;\n // 3xx and 4xx errors are not sent by default.\n return statusCode >= 500 || statusCode <= 299;\n}\n"],"names":[],"mappings":"AAEO,MAAM,gBAAA,GAAmB;AAOzB,SAAS,wBAAA,CAAyB,MAAA,EAAe,QAAA,EAA0B,KAAA,EAA8B;AAC9G,EAAA,MAAM,aAAa,KAAA,CAAM,UAAA;AAEzB,EAAA,OAAO,UAAA,IAAc,OAAO,UAAA,IAAc,GAAA;AAC5C;;;;"} |
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, debug, waitForTracingChannelBinding } 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 = "LruMemoizer"; | ||
| const _lruMemoizerChannelIntegration = (() => { | ||
| return { | ||
| name: INTEGRATION_NAME, | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| DEBUG_BUILD && debug.log(`[orchestrion:lru-memoizer] subscribing to channel "${CHANNELS.LRU_MEMOIZER_LOAD}"`); | ||
| waitForTracingChannelBinding(() => { | ||
| bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(CHANNELS.LRU_MEMOIZER_LOAD), | ||
| // We only want the helper's caller-context restore for the callback lru-memoizer fires from a detached `setImmediate`. | ||
| () => void 0 | ||
| ); | ||
| }); | ||
| } | ||
| }; | ||
| }); | ||
| const lruMemoizerChannelIntegration = defineIntegration(_lruMemoizerChannelIntegration); | ||
| export { lruMemoizerChannelIntegration }; | ||
| //# sourceMappingURL=lru-memoizer.js.map |
| {"version":3,"file":"lru-memoizer.js","sources":["../../../../src/integrations/tracing-channel/lru-memoizer.ts"],"sourcesContent":["import * as diagnosticsChannel from 'node:diagnostics_channel';\nimport type { IntegrationFn } from '@sentry/core';\nimport { debug, defineIntegration, waitForTracingChannelBinding } 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\n// 'LruMemoizer' integration is omitted from the default set.\nconst INTEGRATION_NAME = 'LruMemoizer' as const;\n\ninterface LruMemoizerLoadContext {\n arguments: unknown[];\n}\n\nconst _lruMemoizerChannelIntegration = (() => {\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:lru-memoizer] subscribing to channel \"${CHANNELS.LRU_MEMOIZER_LOAD}\"`);\n\n waitForTracingChannelBinding(() => {\n bindTracingChannelToSpan(\n diagnosticsChannel.tracingChannel<LruMemoizerLoadContext>(CHANNELS.LRU_MEMOIZER_LOAD),\n // We only want the helper's caller-context restore for the callback lru-memoizer fires from a detached `setImmediate`.\n () => undefined,\n );\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * EXPERIMENTAL — orchestrion-driven lru-memoizer integration. Subscribes to\n * `orchestrion:lru-memoizer:load` (injected into `lru-memoizer/lib/async.js`'s\n * `memoizedFunction`). Creates no spans; only re-runs the memoized callback with the\n * caller's scope. Requires the orchestrion runtime hook or bundler plugin.\n */\nexport const lruMemoizerChannelIntegration = defineIntegration(_lruMemoizerChannelIntegration);\n"],"names":[],"mappings":";;;;;;AASA,MAAM,gBAAA,GAAmB,aAAA;AAMzB,MAAM,kCAAkC,MAAM;AAC5C,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,mBAAmB,cAAA,EAAgB;AACtC,QAAA;AAAA,MACF;AAEA,MAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,CAAA,mDAAA,EAAsD,QAAA,CAAS,iBAAiB,CAAA,CAAA,CAAG,CAAA;AAE5G,MAAA,4BAAA,CAA6B,MAAM;AACjC,QAAA,wBAAA;AAAA,UACE,kBAAA,CAAmB,cAAA,CAAuC,QAAA,CAAS,iBAAiB,CAAA;AAAA;AAAA,UAEpF,MAAM;AAAA,SACR;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAQO,MAAM,6BAAA,GAAgC,kBAAkB,8BAA8B;;;;"} |
| import { FastifyReply, FastifyRequest } from './types'; | ||
| /** | ||
| * Subscribe to the Fastify v5 error diagnostics channel. | ||
| */ | ||
| export declare function subscribeToFastifyErrorChannel(): void; | ||
| /** | ||
| * Handle a Fastify error, and possibly send it to Sentry. | ||
| */ | ||
| export declare function handleFastifyError(this: { | ||
| diagnosticsChannelExists?: boolean; | ||
| }, error: Error, request: FastifyRequest, reply: FastifyReply, handlerOrigin: 'diagnostics-channel' | 'onError-hook'): void; | ||
| //# sourceMappingURL=errors.d.ts.map |
| import { FastifyReply, FastifyRequest } from './types'; | ||
| import { handleFastifyError as _handleFastifyError } from './errors'; | ||
| /** | ||
| * Options for the Fastify integration. | ||
| * | ||
| * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry | ||
| * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel. | ||
| * Fastify v3 and v4 use `setupFastifyErrorHandler` instead. | ||
| * | ||
| * @example | ||
| * | ||
| * ```javascript | ||
| * Sentry.init({ | ||
| * integrations: [ | ||
| * Sentry.fastifyIntegration({ | ||
| * shouldHandleError(_error, _request, reply) { | ||
| * return reply.statusCode >= 500; | ||
| * }, | ||
| * }); | ||
| * }, | ||
| * }); | ||
| * ``` | ||
| * | ||
| */ | ||
| interface FastifyIntegrationOptions { | ||
| /** | ||
| * Callback method deciding whether error should be captured and sent to Sentry | ||
| * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel. | ||
| * Fastify v3 and v4 use `setupFastifyErrorHandler` instead. | ||
| * | ||
| * @param error Captured Fastify error | ||
| * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath) | ||
| * @param reply Fastify reply (or any object containing at least statusCode) | ||
| */ | ||
| shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean; | ||
| } | ||
| /** | ||
| * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/). | ||
| * This integration supports Fastify v5 only. | ||
| * | ||
| * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/). | ||
| * | ||
| * @example | ||
| * ```javascript | ||
| * const Sentry = require('@sentry/node'); | ||
| * | ||
| * Sentry.init({ | ||
| * integrations: [Sentry.fastifyIntegration()], | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export declare const fastifyIntegration: (options?: Partial<FastifyIntegrationOptions> | undefined) => import("@sentry/core").Integration & { | ||
| name: string; | ||
| }; | ||
| /** | ||
| * @deprecated This export is deprecated and will not longer be exposed in the next major version. | ||
| */ | ||
| export declare const instrumentFastify: (() => void) & { | ||
| id: string; | ||
| }; | ||
| /** | ||
| * @deprecated This export is deprecated and will not longer be exposed in the next major version. | ||
| */ | ||
| export declare const handleFastifyError: typeof _handleFastifyError; | ||
| export {}; | ||
| //# sourceMappingURL=index.d.ts.map |
| /** | ||
| * Set up the Fastify (>= 3.21.0 < 6) instrumentation by subscribing to the `fastify.initialization` | ||
| * diagnostics channel and registering the span-creating plugin on every Fastify instance. | ||
| * | ||
| * Idempotent and exposes an `id` so it can participate in the OpenTelemetry preload list. | ||
| */ | ||
| export declare const instrumentFastify: (() => void) & { | ||
| id: string; | ||
| }; | ||
| //# sourceMappingURL=instrumentation.d.ts.map |
| import { Integration } from '@sentry/core'; | ||
| type HandlerOriginal = ((request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => Promise<void>) | ((request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => void); | ||
| type FastifyError = any; | ||
| type HookHandlerDoneFunction = <TError extends Error = FastifyError>(err?: TError) => void; | ||
| export interface FastifyInstance { | ||
| version: string; | ||
| register: (plugin: any) => FastifyInstance; | ||
| decorate: (key: string | symbol, value: unknown) => void; | ||
| decorateRequest: (key: string | symbol, value: unknown) => void; | ||
| setNotFoundHandler: (hooks: any, handler?: any) => void; | ||
| after: (listener?: (err: Error) => void) => FastifyInstance; | ||
| addHook(hook: string, handler: HandlerOriginal): FastifyInstance; | ||
| addHook(hook: 'onError', handler: (request: FastifyRequest, reply: FastifyReply, error: Error) => void): FastifyInstance; | ||
| addHook(hook: 'onRequest', handler: (request: FastifyRequest, reply: FastifyReply) => void): FastifyInstance; | ||
| } | ||
| export interface FastifyReply { | ||
| send: () => FastifyReply; | ||
| statusCode: number; | ||
| } | ||
| export interface FastifyRequest { | ||
| method?: string; | ||
| routeOptions?: { | ||
| url?: string; | ||
| }; | ||
| routerPath?: string; | ||
| } | ||
| export interface FastifyIntegration extends Integration { | ||
| getShouldHandleError: () => (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean; | ||
| setShouldHandleError: (shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean) => void; | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=types.d.ts.map |
| import { FastifyReply, FastifyRequest } from './types'; | ||
| export declare const INTEGRATION_NAME = "Fastify"; | ||
| /** | ||
| * Default function to determine if an error should be sent to Sentry | ||
| * | ||
| * 3xx and 4xx errors are not sent by default. | ||
| */ | ||
| export declare function defaultShouldHandleError(_error: Error, _request: FastifyRequest, reply: FastifyReply): boolean; | ||
| //# sourceMappingURL=utils.d.ts.map |
| /** | ||
| * EXPERIMENTAL — orchestrion-driven lru-memoizer integration. Subscribes to | ||
| * `orchestrion:lru-memoizer:load` (injected into `lru-memoizer/lib/async.js`'s | ||
| * `memoizedFunction`). Creates no spans; only re-runs the memoized callback with the | ||
| * caller's scope. Requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const lruMemoizerChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "LruMemoizer"; | ||
| }; | ||
| //# sourceMappingURL=lru-memoizer.d.ts.map |
| /** | ||
| * Ambient shim for `node:diagnostics_channel`, injected into the TS 3.8 type output only | ||
| * (see `scripts/inject-ts38-shims.mjs`). | ||
| * | ||
| * `@types/node@14` — used by the SDK's TS 3.8 compatibility check — predates this module, so the | ||
| * published declarations that re-export `TracingChannel`/`TracingChannelSubscribers` fail to resolve | ||
| * it (`TS2307`). The real shapes are irrelevant here: TS 3.8 consumers only need these to type-check, | ||
| * never to call. This file is deliberately kept out of `src/` so it never participates in the modern | ||
| * build, where `@types/node` already declares the module. | ||
| */ | ||
| declare module 'node:diagnostics_channel' { | ||
| export interface TracingChannelSubscribers<ContextType = unknown> { | ||
| [key: string]: unknown; | ||
| } | ||
| export interface TracingChannel<StoreType = unknown, ContextType = unknown> { | ||
| [key: string]: unknown; | ||
| } | ||
| } |
| import type { FastifyReply, FastifyRequest } from './types'; | ||
| /** | ||
| * Subscribe to the Fastify v5 error diagnostics channel. | ||
| */ | ||
| export declare function subscribeToFastifyErrorChannel(): void; | ||
| /** | ||
| * Handle a Fastify error, and possibly send it to Sentry. | ||
| */ | ||
| export declare function handleFastifyError(this: { | ||
| diagnosticsChannelExists?: boolean; | ||
| }, error: Error, request: FastifyRequest, reply: FastifyReply, handlerOrigin: 'diagnostics-channel' | 'onError-hook'): void; | ||
| //# sourceMappingURL=errors.d.ts.map |
| {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../../../src/integrations/tracing-channel/fastify/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAsB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAWhF;;GAEG;AACH,wBAAgB,8BAA8B,IAAI,IAAI,CAUrD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE;IACJ,wBAAwB,CAAC,EAAE,OAAO,CAAC;CACpC,EACD,KAAK,EAAE,KAAK,EACZ,OAAO,EAAE,cAAc,EACvB,KAAK,EAAE,YAAY,EACnB,aAAa,EAAE,qBAAqB,GAAG,cAAc,GACpD,IAAI,CA0BN"} |
| import type { FastifyReply, FastifyRequest } from './types'; | ||
| import { handleFastifyError as _handleFastifyError } from './errors'; | ||
| /** | ||
| * Options for the Fastify integration. | ||
| * | ||
| * `shouldHandleError` - Callback method deciding whether error should be captured and sent to Sentry | ||
| * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel. | ||
| * Fastify v3 and v4 use `setupFastifyErrorHandler` instead. | ||
| * | ||
| * @example | ||
| * | ||
| * ```javascript | ||
| * Sentry.init({ | ||
| * integrations: [ | ||
| * Sentry.fastifyIntegration({ | ||
| * shouldHandleError(_error, _request, reply) { | ||
| * return reply.statusCode >= 500; | ||
| * }, | ||
| * }); | ||
| * }, | ||
| * }); | ||
| * ``` | ||
| * | ||
| */ | ||
| interface FastifyIntegrationOptions { | ||
| /** | ||
| * Callback method deciding whether error should be captured and sent to Sentry | ||
| * This is used on Fastify v5 where Sentry handles errors in the diagnostics channel. | ||
| * Fastify v3 and v4 use `setupFastifyErrorHandler` instead. | ||
| * | ||
| * @param error Captured Fastify error | ||
| * @param request Fastify request (or any object containing at least method, routeOptions.url, and routerPath) | ||
| * @param reply Fastify reply (or any object containing at least statusCode) | ||
| */ | ||
| shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean; | ||
| } | ||
| /** | ||
| * Adds Sentry tracing instrumentation for [Fastify](https://fastify.dev/). | ||
| * This integration supports Fastify v5 only. | ||
| * | ||
| * For more information, see the [fastify documentation](https://docs.sentry.io/platforms/javascript/guides/fastify/). | ||
| * | ||
| * @example | ||
| * ```javascript | ||
| * const Sentry = require('@sentry/node'); | ||
| * | ||
| * Sentry.init({ | ||
| * integrations: [Sentry.fastifyIntegration()], | ||
| * }) | ||
| * ``` | ||
| */ | ||
| export declare const fastifyIntegration: (options?: Partial<FastifyIntegrationOptions> | undefined) => import("@sentry/core").Integration & { | ||
| name: string; | ||
| }; | ||
| /** | ||
| * @deprecated This export is deprecated and will not longer be exposed in the next major version. | ||
| */ | ||
| export declare const instrumentFastify: (() => void) & { | ||
| id: string; | ||
| }; | ||
| /** | ||
| * @deprecated This export is deprecated and will not longer be exposed in the next major version. | ||
| */ | ||
| export declare const handleFastifyError: typeof _handleFastifyError; | ||
| export {}; | ||
| //# sourceMappingURL=index.d.ts.map |
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/integrations/tracing-channel/fastify/index.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAsB,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAIhF,OAAO,EAAkC,kBAAkB,IAAI,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAErG;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,UAAU,yBAAyB;IACjC;;;;;;;;OAQG;IACH,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;CAC5F;AAsBD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,kBAAkB;;CAE9B,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB;;CAAqB,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,kBAAkB,4BAAsB,CAAC"} |
| /** | ||
| * Set up the Fastify (>= 3.21.0 < 6) instrumentation by subscribing to the `fastify.initialization` | ||
| * diagnostics channel and registering the span-creating plugin on every Fastify instance. | ||
| * | ||
| * Idempotent and exposes an `id` so it can participate in the OpenTelemetry preload list. | ||
| */ | ||
| export declare const instrumentFastify: (() => void) & { | ||
| id: string; | ||
| }; | ||
| //# sourceMappingURL=instrumentation.d.ts.map |
| {"version":3,"file":"instrumentation.d.ts","sourceRoot":"","sources":["../../../../../src/integrations/tracing-channel/fastify/instrumentation.ts"],"names":[],"mappings":"AA+XA;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,SACE,IAAI;;CAmBnC,CAAC"} |
| import type { Integration } from '@sentry/core'; | ||
| type HandlerOriginal = ((request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => Promise<void>) | ((request: FastifyRequest, reply: FastifyReply, done: HookHandlerDoneFunction) => void); | ||
| type FastifyError = any; | ||
| type HookHandlerDoneFunction = <TError extends Error = FastifyError>(err?: TError) => void; | ||
| export interface FastifyInstance { | ||
| version: string; | ||
| register: (plugin: any) => FastifyInstance; | ||
| decorate: (key: string | symbol, value: unknown) => void; | ||
| decorateRequest: (key: string | symbol, value: unknown) => void; | ||
| setNotFoundHandler: (hooks: any, handler?: any) => void; | ||
| after: (listener?: (err: Error) => void) => FastifyInstance; | ||
| addHook(hook: string, handler: HandlerOriginal): FastifyInstance; | ||
| addHook(hook: 'onError', handler: (request: FastifyRequest, reply: FastifyReply, error: Error) => void): FastifyInstance; | ||
| addHook(hook: 'onRequest', handler: (request: FastifyRequest, reply: FastifyReply) => void): FastifyInstance; | ||
| } | ||
| export interface FastifyReply { | ||
| send: () => FastifyReply; | ||
| statusCode: number; | ||
| } | ||
| export interface FastifyRequest { | ||
| method?: string; | ||
| routeOptions?: { | ||
| url?: string; | ||
| }; | ||
| routerPath?: string; | ||
| } | ||
| export interface FastifyIntegration extends Integration { | ||
| getShouldHandleError: () => (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean; | ||
| setShouldHandleError: (shouldHandleError: (error: Error, request: FastifyRequest, reply: FastifyReply) => boolean) => void; | ||
| } | ||
| export {}; | ||
| //# sourceMappingURL=types.d.ts.map |
| {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/integrations/tracing-channel/fastify/types.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,KAAK,eAAe,GAChB,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,uBAAuB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,GAChG,CAAC,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,IAAI,EAAE,uBAAuB,KAAK,IAAI,CAAC,CAAC;AAE5F,KAAK,YAAY,GAAG,GAAG,CAAC;AAExB,KAAK,uBAAuB,GAAG,CAAC,MAAM,SAAS,KAAK,GAAG,YAAY,EAAE,GAAG,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;AAE3F,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,CAAC,MAAM,EAAE,GAAG,KAAK,eAAe,CAAC;IAC3C,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACzD,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IAChE,kBAAkB,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,GAAG,KAAK,IAAI,CAAC;IACxD,KAAK,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,KAAK,eAAe,CAAC;IAC5D,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,GAAG,eAAe,CAAC;IACjE,OAAO,CACL,IAAI,EAAE,SAAS,EACf,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,GAC5E,eAAe,CAAC;IACnB,OAAO,CAAC,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,IAAI,GAAG,eAAe,CAAC;CAC9G;AAED,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,YAAY,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,cAAc;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,YAAY,CAAC,EAAE;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IACF,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,kBAAmB,SAAQ,WAAW;IACrD,oBAAoB,EAAE,MAAM,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC;IAEpG,oBAAoB,EAAE,CACpB,iBAAiB,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,KACvF,IAAI,CAAC;CACX"} |
| import type { FastifyReply, FastifyRequest } from './types'; | ||
| export declare const INTEGRATION_NAME = "Fastify"; | ||
| /** | ||
| * Default function to determine if an error should be sent to Sentry | ||
| * | ||
| * 3xx and 4xx errors are not sent by default. | ||
| */ | ||
| export declare function defaultShouldHandleError(_error: Error, _request: FastifyRequest, reply: FastifyReply): boolean; | ||
| //# sourceMappingURL=utils.d.ts.map |
| {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../../../src/integrations/tracing-channel/fastify/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE5D,eAAO,MAAM,gBAAgB,YAAY,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,GAAG,OAAO,CAI9G"} |
| /** | ||
| * EXPERIMENTAL — orchestrion-driven lru-memoizer integration. Subscribes to | ||
| * `orchestrion:lru-memoizer:load` (injected into `lru-memoizer/lib/async.js`'s | ||
| * `memoizedFunction`). Creates no spans; only re-runs the memoized callback with the | ||
| * caller's scope. Requires the orchestrion runtime hook or bundler plugin. | ||
| */ | ||
| export declare const lruMemoizerChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "LruMemoizer"; | ||
| }; | ||
| //# sourceMappingURL=lru-memoizer.d.ts.map |
| {"version":3,"file":"lru-memoizer.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/lru-memoizer.ts"],"names":[],"mappings":"AAqCA;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B;;CAAoD,CAAC"} |
@@ -5,3 +5,4 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const tracingChannel = require('./tracing-channel.js'); | ||
| const index = require('./vercel-ai/index.js'); | ||
| const index$1 = require('./vercel-ai/index.js'); | ||
| const index = require('./integrations/tracing-channel/fastify/index.js'); | ||
@@ -17,3 +18,6 @@ | ||
| exports.bindTracingChannelToSpan = tracingChannel.bindTracingChannelToSpan; | ||
| exports.vercelAiIntegration = index.vercelAiIntegration; | ||
| exports.vercelAiIntegration = index$1.vercelAiIntegration; | ||
| exports.fastifyIntegration = index.fastifyIntegration; | ||
| exports.handleFastifyError = index.handleFastifyError; | ||
| exports.instrumentFastify = index.instrumentFastify; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const dc = require('node:diagnostics_channel'); | ||
| 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'); | ||
@@ -20,88 +21,49 @@ const INTEGRATION_NAME = "Mysql"; | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| debugBuild.DEBUG_BUILD && core.debug.log(`[orchestrion:mysql] subscribing to channel "${channels.CHANNELS.MYSQL_QUERY}"`); | ||
| const queryCh = dc.tracingChannel(channels.CHANNELS.MYSQL_QUERY); | ||
| const spans = /* @__PURE__ */ new WeakMap(); | ||
| const parentScopes = /* @__PURE__ */ new WeakMap(); | ||
| queryCh.subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| const sql = extractSql(ctx.arguments[0]); | ||
| const { host, port, database, user } = getConnectionConfig(ctx.self); | ||
| const portNumber = typeof port === "string" ? parseInt(port, 10) : port; | ||
| const portIsNumber = typeof portNumber === "number" && !isNaN(portNumber); | ||
| const span = core.startInactiveSpan({ | ||
| name: sql ?? "mysql.query", | ||
| op: "db", | ||
| attributes: { | ||
| [ATTR_DB_SYSTEM]: "mysql", | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.db.orchestrion.mysql", | ||
| [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : void 0, database), | ||
| ...database ? { [ATTR_DB_NAME]: database } : {}, | ||
| ...user ? { [ATTR_DB_USER]: user } : {}, | ||
| ...sql ? { [ATTR_DB_STATEMENT]: sql } : {}, | ||
| ...host ? { [ATTR_NET_PEER_NAME]: host } : {}, | ||
| ...portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {} | ||
| core.waitForTracingChannelBinding(() => { | ||
| tracingChannel.bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(channels.CHANNELS.MYSQL_QUERY), | ||
| (data) => { | ||
| const sql = extractSql(data.arguments[0]); | ||
| const { host, port, database, user } = getConnectionConfig(data.self); | ||
| const portNumber = typeof port === "string" ? parseInt(port, 10) : port; | ||
| const portIsNumber = typeof portNumber === "number" && !isNaN(portNumber); | ||
| data._sentryCallerScope = core.getCurrentScope(); | ||
| return core.startInactiveSpan({ | ||
| name: sql ?? "mysql.query", | ||
| op: "db", | ||
| attributes: { | ||
| [ATTR_DB_SYSTEM]: "mysql", | ||
| [core.SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.db.orchestrion.mysql", | ||
| [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : void 0, database), | ||
| ...database ? { [ATTR_DB_NAME]: database } : {}, | ||
| ...user ? { [ATTR_DB_USER]: user } : {}, | ||
| ...sql ? { [ATTR_DB_STATEMENT]: sql } : {}, | ||
| ...host ? { [ATTR_NET_PEER_NAME]: host } : {}, | ||
| ...portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {} | ||
| } | ||
| }); | ||
| }, | ||
| { | ||
| // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the | ||
| // emitter's `'end'`/`'error'`, not the channel, so defer ending to those. | ||
| 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; | ||
| } | ||
| }); | ||
| spans.set(rawCtx, span); | ||
| const scope = core.getCurrentScope(); | ||
| parentScopes.set(rawCtx, scope); | ||
| if (ctx.arguments.length > 0) { | ||
| const cbIdx = ctx.arguments.length - 1; | ||
| const orchestrionWrappedCb = ctx.arguments[cbIdx]; | ||
| if (typeof orchestrionWrappedCb === "function") { | ||
| const wrapped = orchestrionWrappedCb; | ||
| ctx.arguments[cbIdx] = function(...args) { | ||
| return core.withScope(scope, () => wrapped.apply(this, args)); | ||
| }; | ||
| } | ||
| } | ||
| }, | ||
| end(rawCtx) { | ||
| const ctx = rawCtx; | ||
| if (ctx.error !== void 0) { | ||
| finishSpan(rawCtx); | ||
| return; | ||
| } | ||
| const result = ctx.result; | ||
| if (result && typeof result === "object" && hasOnMethod(result)) { | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| const parentScope = parentScopes.get(rawCtx); | ||
| if (parentScope) { | ||
| core.bindScopeToEmitter(result, parentScope); | ||
| } | ||
| result.on("error", (err) => { | ||
| span.setStatus({ | ||
| code: core.SPAN_STATUS_ERROR, | ||
| message: err instanceof Error ? err.message : "unknown_error" | ||
| }); | ||
| finishSpan(rawCtx); | ||
| }); | ||
| result.on("end", () => finishSpan(rawCtx)); | ||
| return; | ||
| } | ||
| }, | ||
| error(rawCtx) { | ||
| const ctx = rawCtx; | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| span.setStatus({ | ||
| code: core.SPAN_STATUS_ERROR, | ||
| message: ctx.error instanceof Error ? ctx.error.message : "unknown_error" | ||
| }); | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd(rawCtx) { | ||
| finishSpan(rawCtx); | ||
| } | ||
| ); | ||
| }); | ||
| function finishSpan(rawCtx) { | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| span.end(); | ||
| spans.delete(rawCtx); | ||
| parentScopes.delete(rawCtx); | ||
| } | ||
| } | ||
@@ -108,0 +70,0 @@ }; |
@@ -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, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\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';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `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 wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\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 DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = 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 spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\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","diagnosticsChannel","startInactiveSpan","SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN","getCurrentScope","withScope","bindScopeToEmitter","SPAN_STATUS_ERROR","defineIntegration"],"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 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":"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"} |
| Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const CHANNELS = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query" | ||
| MYSQL_QUERY: "orchestrion:mysql:query", | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| }; | ||
@@ -6,0 +7,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} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":[],"mappings":";;AAaO,MAAM,QAAA,GAAW;AAAA,EACtB,WAAA,EAAa;AACf;;;;"} | ||
| {"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;;;;"} |
@@ -23,2 +23,8 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| 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" } | ||
| } | ||
@@ -25,0 +31,0 @@ ]; |
@@ -1,1 +0,1 @@ | ||
| {"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\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;AAE3D;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;;;;;;"} | ||
| {"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;;;;;;"} |
@@ -5,2 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const mysql = require('../integrations/tracing-channel/mysql.js'); | ||
| const lruMemoizer = require('../integrations/tracing-channel/lru-memoizer.js'); | ||
@@ -11,2 +12,3 @@ | ||
| exports.mysqlChannelIntegration = mysql.mysqlChannelIntegration; | ||
| exports.lruMemoizerChannelIntegration = lruMemoizer.lruMemoizerChannelIntegration; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;"} |
@@ -5,2 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const debugBuild = require('./debug-build.js'); | ||
| const attributes = require('@sentry/conventions/attributes'); | ||
@@ -12,2 +13,3 @@ const NOOP = () => { | ||
| const beforeSpanEnd = opts?.beforeSpanEnd; | ||
| const deferSpanEnd = opts?.deferSpanEnd; | ||
| const getErrorHint = (e) => { | ||
@@ -24,2 +26,23 @@ if (typeof opts?.captureError === "function") { | ||
| }; | ||
| const annotateSpanError = (span, error) => { | ||
| if (opts?.captureError) { | ||
| core.captureException(error, getErrorHint(error)); | ||
| } | ||
| const { message, attributes } = getErrorInfo(error); | ||
| span.setStatus({ code: core.SPAN_STATUS_ERROR, message }); | ||
| span.setAttributes(attributes); | ||
| }; | ||
| const makeDeferredEnd = (span, data) => { | ||
| let ended = false; | ||
| return (error) => { | ||
| if (ended) { | ||
| return; | ||
| } | ||
| ended = true; | ||
| if (error !== void 0) { | ||
| annotateSpanError(span, error); | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
| }; | ||
| }; | ||
| const subscribers = { | ||
@@ -30,2 +53,6 @@ start: NOOP, | ||
| if ("error" in data || "result" in data) { | ||
| const span = data._sentrySpan; | ||
| if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) { | ||
| return; | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
@@ -39,8 +66,9 @@ } | ||
| } | ||
| if (opts?.captureError) { | ||
| core.captureException(data.error, getErrorHint(data.error)); | ||
| } | ||
| span.setStatus({ code: core.SPAN_STATUS_ERROR, message: getErrorMessage(data.error) }); | ||
| annotateSpanError(span, data.error); | ||
| }, | ||
| asyncEnd(data) { | ||
| const span = data._sentrySpan; | ||
| if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) { | ||
| return; | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
@@ -59,3 +87,3 @@ } | ||
| function bindSpanToChannelStore(channel, getSpan) { | ||
| const binding = core._INTERNAL_getTracingChannelBinding(); | ||
| const binding = core.getAsyncContextStrategy(core.getMainCarrier()).getTracingChannelBinding?.(); | ||
| if (!binding) { | ||
@@ -70,5 +98,6 @@ debugBuild.DEBUG_BUILD && core.debug.log("[TracingChannel] Could not access async context binding."); | ||
| channel.start.bindStore(asyncLocalStorage, (data) => { | ||
| data._sentryCallerStore = asyncLocalStorage.getStore(); | ||
| const span = getSpan(data); | ||
| if (!span) { | ||
| return asyncLocalStorage.getStore(); | ||
| return data._sentryCallerStore; | ||
| } | ||
@@ -78,2 +107,5 @@ data._sentrySpan = span; | ||
| }); | ||
| channel.asyncStart.bindStore(asyncLocalStorage, (data) => { | ||
| return data._sentryCallerStore; | ||
| }); | ||
| return { | ||
@@ -83,2 +115,3 @@ channel, | ||
| channel.start.unbindStore(asyncLocalStorage); | ||
| channel.asyncStart.unbindStore(asyncLocalStorage); | ||
| } | ||
@@ -95,7 +128,13 @@ }; | ||
| } | ||
| function getErrorMessage(error) { | ||
| if (error && typeof error === "object" && "message" in error && typeof error.message === "string") { | ||
| return error.message; | ||
| } | ||
| return String(error); | ||
| function getErrorInfo(error) { | ||
| const isObject = !!error && typeof error === "object"; | ||
| const raw = isObject ? "message" in error ? error.message : void 0 : error; | ||
| const message = raw ? String(raw) : "unknown_error"; | ||
| const type = isObject && "name" in error ? String(error.name) : "unknown"; | ||
| return { | ||
| message, | ||
| attributes: { | ||
| [attributes.ERROR_TYPE]: type | ||
| } | ||
| }; | ||
| } | ||
@@ -102,0 +141,0 @@ |
@@ -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 { _INTERNAL_getTracingChannelBinding, debug, captureException, SPAN_STATUS_ERROR } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n _sentrySpan?: Span;\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/** 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 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 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 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 if (opts?.captureError) {\n captureException(data.error, getErrorHint(data.error));\n }\n\n span.setStatus({ code: SPAN_STATUS_ERROR, message: getErrorMessage(data.error) });\n },\n asyncEnd(data) {\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 = _INTERNAL_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 const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return asyncLocalStorage.getStore() as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the store\n channel.start.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\n/** Best-effort short message for a span status: an error-like's `message`, otherwise its string form. */\nfunction getErrorMessage(error: unknown): string {\n if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {\n return error.message;\n }\n return String(error);\n}\n"],"names":["captureException","SPAN_STATUS_ERROR","_INTERNAL_getTracingChannelBinding","DEBUG_BUILD","debug"],"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;\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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"} |
@@ -5,3 +5,3 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); | ||
| const vercelAiDcSubscriber = require('./vercel-ai-dc-subscriber.js'); | ||
| const dc = require('node:diagnostics_channel'); | ||
| const diagnosticsChannel = require('node:diagnostics_channel'); | ||
@@ -12,6 +12,8 @@ const _vercelAiIntegration = ((options = {}) => { | ||
| setupOnce() { | ||
| if (!dc.tracingChannel) { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| void Promise.resolve().then(() => vercelAiDcSubscriber.subscribeVercelAiTracingChannel(dc.tracingChannel, options)); | ||
| core.waitForTracingChannelBinding(() => { | ||
| vercelAiDcSubscriber.subscribeVercelAiTracingChannel(diagnosticsChannel.tracingChannel, options); | ||
| }); | ||
| } | ||
@@ -18,0 +20,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n // The factory needs the Sentry OTel context manager, which `initOpenTelemetry()` registers after `setupOnce`, so defer a tick.\n // Options are passed in here rather than read back off the integration per event.\n void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options));\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":["subscribeVercelAiTracingChannel","defineIntegration"],"mappings":";;;;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,GAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAMA,MAAA,KAAK,OAAA,CAAQ,SAAQ,CAAE,IAAA,CAAK,MAAMA,oDAAA,CAAgC,EAAA,CAAG,cAAA,EAAgB,OAAO,CAAC,CAAA;AAAA,IAC/F;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsBC,uBAAkB,oBAAoB;;;;"} | ||
| {"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, waitForTracingChannelBinding, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n waitForTracingChannelBinding(() => {\n subscribeVercelAiTracingChannel(dc.tracingChannel, options);\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":["dc","waitForTracingChannelBinding","subscribeVercelAiTracingChannel","defineIntegration"],"mappings":";;;;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,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,oDAAA,CAAgCF,kBAAA,CAAG,gBAAgB,OAAO,CAAA;AAAA,MAC5D,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsBG,uBAAkB,oBAAoB;;;;"} |
| 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 { bindTracingChannelToSpan } from './tracing-channel.js'; | ||
| export { vercelAiIntegration } from './vercel-ai/index.js'; | ||
| export { fastifyIntegration, handleFastifyError, instrumentFastify } from './integrations/tracing-channel/fastify/index.js'; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;"} |
@@ -1,5 +0,6 @@ | ||
| import * as dc from 'node:diagnostics_channel'; | ||
| import { defineIntegration, debug, SPAN_STATUS_ERROR, bindScopeToEmitter, startInactiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, getCurrentScope, withScope } from '@sentry/core'; | ||
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
| import { defineIntegration, debug, waitForTracingChannelBinding, bindScopeToEmitter, getCurrentScope, startInactiveSpan, 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'; | ||
@@ -18,88 +19,49 @@ const INTEGRATION_NAME = "Mysql"; | ||
| setupOnce() { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel "${CHANNELS.MYSQL_QUERY}"`); | ||
| const queryCh = dc.tracingChannel(CHANNELS.MYSQL_QUERY); | ||
| const spans = /* @__PURE__ */ new WeakMap(); | ||
| const parentScopes = /* @__PURE__ */ new WeakMap(); | ||
| queryCh.subscribe({ | ||
| start(rawCtx) { | ||
| const ctx = rawCtx; | ||
| const sql = extractSql(ctx.arguments[0]); | ||
| const { host, port, database, user } = getConnectionConfig(ctx.self); | ||
| const portNumber = typeof port === "string" ? parseInt(port, 10) : port; | ||
| const portIsNumber = typeof portNumber === "number" && !isNaN(portNumber); | ||
| const span = startInactiveSpan({ | ||
| name: sql ?? "mysql.query", | ||
| op: "db", | ||
| attributes: { | ||
| [ATTR_DB_SYSTEM]: "mysql", | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.db.orchestrion.mysql", | ||
| [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : void 0, database), | ||
| ...database ? { [ATTR_DB_NAME]: database } : {}, | ||
| ...user ? { [ATTR_DB_USER]: user } : {}, | ||
| ...sql ? { [ATTR_DB_STATEMENT]: sql } : {}, | ||
| ...host ? { [ATTR_NET_PEER_NAME]: host } : {}, | ||
| ...portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {} | ||
| waitForTracingChannelBinding(() => { | ||
| bindTracingChannelToSpan( | ||
| diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY), | ||
| (data) => { | ||
| const sql = extractSql(data.arguments[0]); | ||
| const { host, port, database, user } = getConnectionConfig(data.self); | ||
| const portNumber = typeof port === "string" ? parseInt(port, 10) : port; | ||
| const portIsNumber = typeof portNumber === "number" && !isNaN(portNumber); | ||
| data._sentryCallerScope = getCurrentScope(); | ||
| return startInactiveSpan({ | ||
| name: sql ?? "mysql.query", | ||
| op: "db", | ||
| attributes: { | ||
| [ATTR_DB_SYSTEM]: "mysql", | ||
| [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: "auto.db.orchestrion.mysql", | ||
| [ATTR_DB_CONNECTION_STRING]: getJDBCString(host, portIsNumber ? portNumber : void 0, database), | ||
| ...database ? { [ATTR_DB_NAME]: database } : {}, | ||
| ...user ? { [ATTR_DB_USER]: user } : {}, | ||
| ...sql ? { [ATTR_DB_STATEMENT]: sql } : {}, | ||
| ...host ? { [ATTR_NET_PEER_NAME]: host } : {}, | ||
| ...portIsNumber ? { [ATTR_NET_PEER_PORT]: portNumber } : {} | ||
| } | ||
| }); | ||
| }, | ||
| { | ||
| // No-callback `query(sql)` returns a streamable `Query` emitter as `result`; it settles on the | ||
| // emitter's `'end'`/`'error'`, not the channel, so defer ending to those. | ||
| 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; | ||
| } | ||
| }); | ||
| spans.set(rawCtx, span); | ||
| const scope = getCurrentScope(); | ||
| parentScopes.set(rawCtx, scope); | ||
| if (ctx.arguments.length > 0) { | ||
| const cbIdx = ctx.arguments.length - 1; | ||
| const orchestrionWrappedCb = ctx.arguments[cbIdx]; | ||
| if (typeof orchestrionWrappedCb === "function") { | ||
| const wrapped = orchestrionWrappedCb; | ||
| ctx.arguments[cbIdx] = function(...args) { | ||
| return withScope(scope, () => wrapped.apply(this, args)); | ||
| }; | ||
| } | ||
| } | ||
| }, | ||
| end(rawCtx) { | ||
| const ctx = rawCtx; | ||
| if (ctx.error !== void 0) { | ||
| finishSpan(rawCtx); | ||
| return; | ||
| } | ||
| const result = ctx.result; | ||
| if (result && typeof result === "object" && hasOnMethod(result)) { | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| const parentScope = parentScopes.get(rawCtx); | ||
| if (parentScope) { | ||
| bindScopeToEmitter(result, parentScope); | ||
| } | ||
| result.on("error", (err) => { | ||
| span.setStatus({ | ||
| code: SPAN_STATUS_ERROR, | ||
| message: err instanceof Error ? err.message : "unknown_error" | ||
| }); | ||
| finishSpan(rawCtx); | ||
| }); | ||
| result.on("end", () => finishSpan(rawCtx)); | ||
| return; | ||
| } | ||
| }, | ||
| error(rawCtx) { | ||
| const ctx = rawCtx; | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| span.setStatus({ | ||
| code: SPAN_STATUS_ERROR, | ||
| message: ctx.error instanceof Error ? ctx.error.message : "unknown_error" | ||
| }); | ||
| }, | ||
| asyncStart() { | ||
| }, | ||
| asyncEnd(rawCtx) { | ||
| finishSpan(rawCtx); | ||
| } | ||
| ); | ||
| }); | ||
| function finishSpan(rawCtx) { | ||
| const span = spans.get(rawCtx); | ||
| if (!span) return; | ||
| span.end(); | ||
| spans.delete(rawCtx); | ||
| parentScopes.delete(rawCtx); | ||
| } | ||
| } | ||
@@ -106,0 +68,0 @@ }; |
@@ -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, Span } from '@sentry/core';\nimport {\n bindScopeToEmitter,\n debug,\n defineIntegration,\n getCurrentScope,\n SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN,\n SPAN_STATUS_ERROR,\n startInactiveSpan,\n withScope,\n} from '@sentry/core';\nimport { DEBUG_BUILD } from '../../debug-build';\nimport { CHANNELS } from '../../orchestrion/channels';\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';\n\n// OpenTelemetry \"OLD\" db/net semantic-conventions. We inline them rather than\n// importing `@opentelemetry/semantic-conventions` to keep this integration's\n// dependency surface free of OTel — orchestrion's whole point is to step away\n// from the OTel auto-instrumentation stack.\n//\n// We emit the OLD conventions to match `@opentelemetry/instrumentation-mysql`'s\n// default (it only emits the stable `db.system.name` / `db.query.text` set when\n// `OTEL_SEMCONV_STABILITY_OPT_IN=database` is opted into) and the rest of the\n// Sentry JS SDK, whose `inferDbSpanData` processor renames spans based on\n// `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 wrapCallback transform attaches to the tracing-channel\n * `context` object. Documented here rather than imported because orchestrion's\n * runtime doesn't export it — see `node_modules/@apm-js-collab/code-transformer/lib/transforms.js`.\n *\n * `arguments` is the *live* args array passed to the wrapped function: orchestrion\n * splices the user's callback out and inserts its own wrapper at the same index\n * before publishing `start`. The `start` hook re-wraps that entry to restore the\n * caller's scope across mysql's async callback dispatch (see below).\n */\ninterface MysqlQueryChannelContext {\n arguments: unknown[];\n self?: MysqlConnection;\n moduleVersion?: string;\n result?: unknown;\n error?: unknown;\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 DEBUG_BUILD && debug.log(`[orchestrion:mysql] subscribing to channel \"${CHANNELS.MYSQL_QUERY}\"`);\n const queryCh = diagnosticsChannel.tracingChannel(CHANNELS.MYSQL_QUERY);\n\n // Orchestrion creates one `context` object per call, shared across all\n // lifecycle hooks. We key both maps off that identity; `WeakMap` so an\n // unfinished path can't leak its entries.\n const spans = new WeakMap<object, Span>();\n // The scope active when the query was issued, consumed in `end` to bind\n // the streamed `Query` emitter's listeners to it.\n const parentScopes = new WeakMap<object, Scope>();\n\n // `subscribe()` requires all five lifecycle hooks. The orchestrion\n // `wrapAuto` transform fires events in one of four orders depending on\n // call shape:\n // - sync throw : start → error → end\n // (NO asyncEnd)\n // - async-callback error : start → end → error →\n // asyncStart → asyncEnd\n // - async-callback success : start → end → asyncStart →\n // asyncEnd\n // - no-callback (streamable Query) : start → end\n // (ctx.result is the Query\n // emitter, no async events)\n //\n // Where the span closes depends on the path: `asyncEnd` for callbacks (so\n // it spans the full round-trip + callback), or `end` for the sync-throw\n // and streamable paths. The `end` hook tells those apart via `ctx.error`\n // / `ctx.result` — see there.\n queryCh.subscribe({\n start(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const sql = extractSql(ctx.arguments[0]);\n const { host, port, database, user } = getConnectionConfig(ctx.self);\n const portNumber = typeof port === 'string' ? parseInt(port, 10) : port;\n const portIsNumber = typeof portNumber === 'number' && !isNaN(portNumber);\n\n const span = 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 spans.set(rawCtx, span);\n\n // Capture the scope while we're still synchronously inside the\n // caller's `connection.query` call. mysql v2 drains callbacks and\n // emits streamed-query events from its socket data handler, where the\n // AsyncLocalStorage store backing the active span no longer reflects\n // the caller's context — and `asyncStart`/`asyncEnd` fire from that\n // same lost context, so capturing has to happen now.\n const scope = getCurrentScope();\n parentScopes.set(rawCtx, scope);\n\n // Callback path: orchestrion has spliced the user's callback out of\n // `ctx.arguments` and put its own wrapper (`__apm$wrappedCb`) at the\n // same index. Re-wrap it so the callback — and any nested\n // `connection.query(...)` — runs with the captured scope active.\n if (ctx.arguments.length > 0) {\n const cbIdx = ctx.arguments.length - 1;\n const orchestrionWrappedCb = ctx.arguments[cbIdx];\n if (typeof orchestrionWrappedCb === 'function') {\n const wrapped = orchestrionWrappedCb as (...a: unknown[]) => unknown;\n ctx.arguments[cbIdx] = function (this: unknown, ...args: unknown[]): unknown {\n return withScope(scope, () => wrapped.apply(this, args));\n };\n }\n }\n },\n\n end(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n\n // Sync throw: `end` fires AFTER `error` (both inside the wrapper's\n // `try/catch/finally`), so `ctx.error` is already set. Close the\n // span now since no `asyncEnd` will fire.\n if (ctx.error !== undefined) {\n finishSpan(rawCtx);\n return;\n }\n\n // No-callback (streamable Query) path: orchestrion's `wrapPromise`\n // stores the synchronous return value on `ctx.result` and never\n // fires `asyncStart`/`asyncEnd`. The returned `Query` is an\n // `EventEmitter` that emits `'end'` on success and `'error'` on\n // failure — hook those to close the span.\n // Note: a streamed span never finishes if the connection is destroyed\n // mid-flight — mysql then emits neither `'end'` nor `'error'`, so the\n // span is dropped (the `WeakMap` still prevents a leak). Closing this\n // needs connection-level hooks the per-query context doesn't expose.\n const result = ctx.result;\n if (result && typeof result === 'object' && hasOnMethod(result)) {\n const span = spans.get(rawCtx);\n if (!span) return;\n\n // Bind the captured scope to the streamed `Query` emitter: its\n // `'end'`/`'error'`/`'fields'`/… events fire from mysql's socket\n // handler with the caller's context lost, so without this a span\n // started in a user's stream listener would begin a fresh root trace\n // instead of nesting under the parent. `bindScopeToEmitter` patches\n // `on`/`addListener`/… so listeners added after `query()` returns\n // inherit the scope (like OTel's `context.bind`).\n const parentScope = parentScopes.get(rawCtx);\n if (parentScope) {\n bindScopeToEmitter(result, parentScope);\n }\n\n result.on('error', err => {\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: err instanceof Error ? err.message : 'unknown_error',\n });\n // Defensive: end the span here too in case `'end'` never fires\n // (e.g. abrupt socket destruction). `finishSpan` is idempotent —\n // `spans.delete` makes the subsequent `'end'` listener a no-op.\n finishSpan(rawCtx);\n });\n result.on('end', () => finishSpan(rawCtx));\n return;\n }\n\n // Callback path: `asyncEnd` will close the span. Nothing to do here.\n },\n\n error(rawCtx) {\n const ctx = rawCtx as MysqlQueryChannelContext;\n const span = spans.get(rawCtx);\n if (!span) return;\n span.setStatus({\n code: SPAN_STATUS_ERROR,\n message: ctx.error instanceof Error ? ctx.error.message : 'unknown_error',\n });\n },\n\n asyncStart() {\n // No-op: we end on `asyncEnd` so the span covers the full callback duration.\n },\n\n asyncEnd(rawCtx) {\n finishSpan(rawCtx);\n },\n });\n\n function finishSpan(rawCtx: object): void {\n const span = spans.get(rawCtx);\n if (!span) return;\n span.end();\n spans.delete(rawCtx);\n parentScopes.delete(rawCtx);\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":["diagnosticsChannel"],"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 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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"} |
| const CHANNELS = { | ||
| MYSQL_QUERY: "orchestrion:mysql:query" | ||
| MYSQL_QUERY: "orchestrion:mysql:query", | ||
| LRU_MEMOIZER_LOAD: "orchestrion:lru-memoizer:load" | ||
| }; | ||
@@ -4,0 +5,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} as const;\n\nexport type ChannelName = (typeof CHANNELS)[keyof typeof CHANNELS];\n"],"names":[],"mappings":"AAaO,MAAM,QAAA,GAAW;AAAA,EACtB,WAAA,EAAa;AACf;;;;"} | ||
| {"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;;;;"} |
@@ -21,2 +21,8 @@ const SENTRY_INSTRUMENTATIONS = [ | ||
| 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" } | ||
| } | ||
@@ -23,0 +29,0 @@ ]; |
@@ -1,1 +0,1 @@ | ||
| {"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\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;AAE3D;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;;;;"} | ||
| {"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;;;;"} |
| export { detectOrchestrionSetup } from './detect.js'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql.js'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer.js'; | ||
| //# sourceMappingURL=index.js.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";"} | ||
| {"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"} |
@@ -1,1 +0,1 @@ | ||
| {"type":"module","version":"10.62.0","sideEffects":false} | ||
| {"type":"module","version":"10.63.0","sideEffects":false} |
@@ -1,3 +0,4 @@ | ||
| import { _INTERNAL_getTracingChannelBinding, debug, captureException, SPAN_STATUS_ERROR } from '@sentry/core'; | ||
| import { getAsyncContextStrategy, getMainCarrier, debug, captureException, SPAN_STATUS_ERROR } from '@sentry/core'; | ||
| import { DEBUG_BUILD } from './debug-build.js'; | ||
| import { ERROR_TYPE } from '@sentry/conventions/attributes'; | ||
@@ -9,2 +10,3 @@ const NOOP = () => { | ||
| const beforeSpanEnd = opts?.beforeSpanEnd; | ||
| const deferSpanEnd = opts?.deferSpanEnd; | ||
| const getErrorHint = (e) => { | ||
@@ -21,2 +23,23 @@ if (typeof opts?.captureError === "function") { | ||
| }; | ||
| const annotateSpanError = (span, error) => { | ||
| if (opts?.captureError) { | ||
| captureException(error, getErrorHint(error)); | ||
| } | ||
| const { message, attributes } = getErrorInfo(error); | ||
| span.setStatus({ code: SPAN_STATUS_ERROR, message }); | ||
| span.setAttributes(attributes); | ||
| }; | ||
| const makeDeferredEnd = (span, data) => { | ||
| let ended = false; | ||
| return (error) => { | ||
| if (ended) { | ||
| return; | ||
| } | ||
| ended = true; | ||
| if (error !== void 0) { | ||
| annotateSpanError(span, error); | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
| }; | ||
| }; | ||
| const subscribers = { | ||
@@ -27,2 +50,6 @@ start: NOOP, | ||
| if ("error" in data || "result" in data) { | ||
| const span = data._sentrySpan; | ||
| if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) { | ||
| return; | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
@@ -36,8 +63,9 @@ } | ||
| } | ||
| if (opts?.captureError) { | ||
| captureException(data.error, getErrorHint(data.error)); | ||
| } | ||
| span.setStatus({ code: SPAN_STATUS_ERROR, message: getErrorMessage(data.error) }); | ||
| annotateSpanError(span, data.error); | ||
| }, | ||
| asyncEnd(data) { | ||
| const span = data._sentrySpan; | ||
| if (span && deferSpanEnd?.({ span, data, end: makeDeferredEnd(span, data) })) { | ||
| return; | ||
| } | ||
| endBoundSpan(data, beforeSpanEnd); | ||
@@ -56,3 +84,3 @@ } | ||
| function bindSpanToChannelStore(channel, getSpan) { | ||
| const binding = _INTERNAL_getTracingChannelBinding(); | ||
| const binding = getAsyncContextStrategy(getMainCarrier()).getTracingChannelBinding?.(); | ||
| if (!binding) { | ||
@@ -67,5 +95,6 @@ DEBUG_BUILD && debug.log("[TracingChannel] Could not access async context binding."); | ||
| channel.start.bindStore(asyncLocalStorage, (data) => { | ||
| data._sentryCallerStore = asyncLocalStorage.getStore(); | ||
| const span = getSpan(data); | ||
| if (!span) { | ||
| return asyncLocalStorage.getStore(); | ||
| return data._sentryCallerStore; | ||
| } | ||
@@ -75,2 +104,5 @@ data._sentrySpan = span; | ||
| }); | ||
| channel.asyncStart.bindStore(asyncLocalStorage, (data) => { | ||
| return data._sentryCallerStore; | ||
| }); | ||
| return { | ||
@@ -80,2 +112,3 @@ channel, | ||
| channel.start.unbindStore(asyncLocalStorage); | ||
| channel.asyncStart.unbindStore(asyncLocalStorage); | ||
| } | ||
@@ -92,7 +125,13 @@ }; | ||
| } | ||
| function getErrorMessage(error) { | ||
| if (error && typeof error === "object" && "message" in error && typeof error.message === "string") { | ||
| return error.message; | ||
| } | ||
| return String(error); | ||
| function getErrorInfo(error) { | ||
| const isObject = !!error && typeof error === "object"; | ||
| const raw = isObject ? "message" in error ? error.message : void 0 : error; | ||
| const message = raw ? String(raw) : "unknown_error"; | ||
| const type = isObject && "name" in error ? String(error.name) : "unknown"; | ||
| return { | ||
| message, | ||
| attributes: { | ||
| [ERROR_TYPE]: type | ||
| } | ||
| }; | ||
| } | ||
@@ -99,0 +138,0 @@ |
@@ -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 { _INTERNAL_getTracingChannelBinding, debug, captureException, SPAN_STATUS_ERROR } from '@sentry/core';\nimport { DEBUG_BUILD } from './debug-build';\n\nexport type TracingChannelPayloadWithSpan<TData extends object> = TData & {\n _sentrySpan?: Span;\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/** 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 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 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 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 if (opts?.captureError) {\n captureException(data.error, getErrorHint(data.error));\n }\n\n span.setStatus({ code: SPAN_STATUS_ERROR, message: getErrorMessage(data.error) });\n },\n asyncEnd(data) {\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 = _INTERNAL_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 const span = getSpan(data);\n if (!span) {\n // Leave the active context untouched so nested operations keep parenting to the enclosing span.\n return asyncLocalStorage.getStore() as TData;\n }\n data._sentrySpan = span;\n\n return binding.getStoreWithActiveSpan(span) as TData;\n });\n\n return {\n channel,\n unbind: () => {\n // Removes the store\n channel.start.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\n/** Best-effort short message for a span status: an error-like's `message`, otherwise its string form. */\nfunction getErrorMessage(error: unknown): string {\n if (error && typeof error === 'object' && 'message' in error && typeof error.message === 'string') {\n return error.message;\n }\n return String(error);\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;\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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"} |
@@ -1,4 +0,4 @@ | ||
| import { defineIntegration } from '@sentry/core'; | ||
| import { defineIntegration, waitForTracingChannelBinding } from '@sentry/core'; | ||
| import { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber.js'; | ||
| import * as dc from 'node:diagnostics_channel'; | ||
| import * as diagnosticsChannel from 'node:diagnostics_channel'; | ||
@@ -9,6 +9,8 @@ const _vercelAiIntegration = ((options = {}) => { | ||
| setupOnce() { | ||
| if (!dc.tracingChannel) { | ||
| if (!diagnosticsChannel.tracingChannel) { | ||
| return; | ||
| } | ||
| void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options)); | ||
| waitForTracingChannelBinding(() => { | ||
| subscribeVercelAiTracingChannel(diagnosticsChannel.tracingChannel, options); | ||
| }); | ||
| } | ||
@@ -15,0 +17,0 @@ }; |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n // The factory needs the Sentry OTel context manager, which `initOpenTelemetry()` registers after `setupOnce`, so defer a tick.\n // Options are passed in here rather than read back off the integration per event.\n void Promise.resolve().then(() => subscribeVercelAiTracingChannel(dc.tracingChannel, options));\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":[],"mappings":";;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,UAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,GAAG,cAAA,EAAgB;AACtB,QAAA;AAAA,MACF;AAMA,MAAA,KAAK,OAAA,CAAQ,SAAQ,CAAE,IAAA,CAAK,MAAM,+BAAA,CAAgC,EAAA,CAAG,cAAA,EAAgB,OAAO,CAAC,CAAA;AAAA,IAC/F;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"} | ||
| {"version":3,"file":"index.js","sources":["../../../src/vercel-ai/index.ts"],"sourcesContent":["import { defineIntegration, waitForTracingChannelBinding, type IntegrationFn } from '@sentry/core';\nimport { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber';\nimport * as dc from 'node:diagnostics_channel';\n\ntype VercelAiOptions = {\n /**\n * Enable or disable input recording. Enabled if `dataCollection.genAI.inputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordInputs?: boolean;\n\n /**\n * Enable or disable output recording. Enabled if `dataCollection.genAI.outputs` (or the deprecated `sendDefaultPii` option) is `true`\n * or if you set `isEnabled` to `true` in your ai SDK method telemetry settings.\n * Integration-level options take precedence over global `dataCollection` config.\n */\n recordOutputs?: boolean;\n\n /**\n * Enable or disable truncation of recorded input messages.\n * Defaults to `true`.\n */\n enableTruncation?: boolean;\n};\n\nconst _vercelAiIntegration = ((options: VercelAiOptions = {}) => {\n return {\n name: 'VercelAI' as const,\n setupOnce() {\n // Bail if this is not available\n if (!dc.tracingChannel) {\n return;\n }\n\n // Subscribe to the `ai` SDK's native telemetry tracing channel (ai >= 7).\n // This is a no-op on versions that don't publish to the channel, so it is always safe to call.\n waitForTracingChannelBinding(() => {\n subscribeVercelAiTracingChannel(dc.tracingChannel, options);\n });\n },\n };\n}) satisfies IntegrationFn;\n\n/**\n * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7).\n */\nexport const vercelAiIntegration = defineIntegration(_vercelAiIntegration);\n"],"names":["dc"],"mappings":";;;;AA0BA,MAAM,oBAAA,IAAwB,CAAC,OAAA,GAA2B,EAAC,KAAM;AAC/D,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,+BAAA,CAAgCA,kBAAA,CAAG,gBAAgB,OAAO,CAAA;AAAA,MAC5D,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAKO,MAAM,mBAAA,GAAsB,kBAAkB,oBAAoB;;;;"} |
@@ -0,1 +1,2 @@ | ||
| /// <reference path="./node-diagnostics-channel.d.ts" /> | ||
| /** | ||
@@ -11,2 +12,3 @@ * Server-only utilities shared across Sentry server SDKs. | ||
| export { vercelAiIntegration } from './vercel-ai'; | ||
| export { fastifyIntegration, handleFastifyError, instrumentFastify, } from './integrations/tracing-channel/fastify'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -9,3 +9,5 @@ /** | ||
| */ | ||
| export declare const mysqlChannelIntegration: () => import("@sentry/core").Integration; | ||
| export declare const mysqlChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Mysql"; | ||
| }; | ||
| //# sourceMappingURL=mysql.d.ts.map |
@@ -16,4 +16,5 @@ /** | ||
| 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 |
| export { detectOrchestrionSetup } from './detect'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| //# sourceMappingURL=index.d.ts.map |
| import { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel'; | ||
| import { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core'; | ||
| export type TracingChannelPayloadWithSpan<TData extends object> = TData & { | ||
| /** | ||
| * The current active span for the traced call. | ||
| */ | ||
| _sentrySpan?: Span; | ||
| /** | ||
| * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing. | ||
| */ | ||
| _sentryCallerStore?: unknown; | ||
| }; | ||
@@ -23,2 +30,17 @@ export interface SentryTracingChannel<TData extends object = object> extends Pick<TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>, Exclude<keyof TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>, 'subscribe' | 'unsubscribe'>> { | ||
| captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext); | ||
| /** | ||
| * Take ownership of *when* the span ends: return `true` and the helper won't end it on | ||
| * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that | ||
| * completes via its own `'end'`/`'error'` events. | ||
| * | ||
| * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span | ||
| * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false` | ||
| * lets the helper end the span as usual. | ||
| */ | ||
| deferSpanEnd?: (args: { | ||
| span: Span; | ||
| data: TracingChannelPayloadWithSpan<TData>; | ||
| /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */ | ||
| end: (error?: unknown) => void; | ||
| }) => boolean; | ||
| } | ||
@@ -25,0 +47,0 @@ /** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */ |
@@ -23,4 +23,6 @@ type VercelAiOptions = { | ||
| */ | ||
| export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration; | ||
| export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| export {}; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -11,2 +11,3 @@ /** | ||
| export { vercelAiIntegration } from './vercel-ai'; | ||
| export { fastifyIntegration, handleFastifyError, instrumentFastify, } from './integrations/tracing-channel/fastify'; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -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"} | ||
| {"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"} |
@@ -9,3 +9,5 @@ /** | ||
| */ | ||
| export declare const mysqlChannelIntegration: () => import("@sentry/core").Integration; | ||
| export declare const mysqlChannelIntegration: () => import("@sentry/core").Integration & { | ||
| name: "Mysql"; | ||
| }; | ||
| //# sourceMappingURL=mysql.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"names":[],"mappings":"AAoRA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,0CAA8C,CAAC"} | ||
| {"version":3,"file":"mysql.d.ts","sourceRoot":"","sources":["../../../../src/integrations/tracing-channel/mysql.ts"],"names":[],"mappings":"AAuKA;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB;;CAA8C,CAAC"} |
@@ -16,4 +16,5 @@ /** | ||
| 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;;CAEX,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":"AAAA;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,QAAQ;;;CAGX,CAAC;AAEX,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,QAAQ,CAAC,CAAC,MAAM,OAAO,QAAQ,CAAC,CAAC"} |
@@ -1,1 +0,1 @@ | ||
| {"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,EAqB1D,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"} | ||
| {"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"} |
| export { detectOrchestrionSetup } from './detect'; | ||
| export { mysqlChannelIntegration } from '../integrations/tracing-channel/mysql'; | ||
| export { lruMemoizerChannelIntegration } from '../integrations/tracing-channel/lru-memoizer'; | ||
| //# 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"} | ||
| {"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"} |
| import type { TracingChannel, TracingChannelSubscribers } from 'node:diagnostics_channel'; | ||
| import type { ExclusiveEventHintOrCaptureContext, Span } from '@sentry/core'; | ||
| export type TracingChannelPayloadWithSpan<TData extends object> = TData & { | ||
| /** | ||
| * The current active span for the traced call. | ||
| */ | ||
| _sentrySpan?: Span; | ||
| /** | ||
| * The context's active store value, used to restore the context for asyncStart continuations for callback-based tracing. | ||
| */ | ||
| _sentryCallerStore?: unknown; | ||
| }; | ||
@@ -23,2 +30,17 @@ export interface SentryTracingChannel<TData extends object = object> extends Omit<TracingChannel<TData, TracingChannelPayloadWithSpan<TData>>, 'subscribe' | 'unsubscribe'> { | ||
| captureError?: boolean | ((e: unknown) => ExclusiveEventHintOrCaptureContext); | ||
| /** | ||
| * Take ownership of *when* the span ends: return `true` and the helper won't end it on | ||
| * `end`/`asyncEnd`. For results that settle out-of-band — e.g. a streamed `EventEmitter` that | ||
| * completes via its own `'end'`/`'error'` events. | ||
| * | ||
| * Call `end` when it settles — `end()` on success, `end(error)` on failure. `end` owns *how* the span | ||
| * ends (error status/attributes, `captureError`, `beforeSpanEnd`) and is idempotent. Default `false` | ||
| * lets the helper end the span as usual. | ||
| */ | ||
| deferSpanEnd?: (args: { | ||
| span: Span; | ||
| data: TracingChannelPayloadWithSpan<TData>; | ||
| /** Ends the span: `end()` on success, `end(error)` on failure. Idempotent. */ | ||
| end: (error?: unknown) => void; | ||
| }) => boolean; | ||
| } | ||
@@ -25,0 +47,0 @@ /** Returned by {@link bindTracingChannelToSpan}: the bound channel plus a teardown handle. */ |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"tracing-channel.d.ts","sourceRoot":"","sources":["../../src/tracing-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,KAAK,EAAE,kCAAkC,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAI7E,MAAM,MAAM,6BAA6B,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG;IACxE,WAAW,CAAC,EAAE,IAAI,CAAC;CACpB,CAAC;AAKF,MAAM,WAAW,oBAAoB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,IAAI,CAC/E,cAAc,CAAC,KAAK,EAAE,6BAA6B,CAAC,KAAK,CAAC,CAAC,EAC3D,WAAW,GAAG,aAAa,CAC5B;IACC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACvG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC1G;AAED,MAAM,WAAW,8BAA8B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC3E;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IAEjF;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,kCAAkC,CAAC,CAAC;CAC/E;AAED,8FAA8F;AAC9F,MAAM,WAAW,2BAA2B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACxE;;OAEG;IACH,OAAO,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAErC;;;OAGG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAID;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,MAAM,EAC3D,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACrC,OAAO,EAAE,CAAC,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,SAAS,EACzE,IAAI,CAAC,EAAE,8BAA8B,CAAC,KAAK,CAAC,GAC3C,2BAA2B,CAAC,KAAK,CAAC,CAuDpC"} | ||
| {"version":3,"file":"tracing-channel.d.ts","sourceRoot":"","sources":["../../src/tracing-channel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAE1F,OAAO,KAAK,EAAE,kCAAkC,EAAE,IAAI,EAAE,MAAM,cAAc,CAAC;AAK7E,MAAM,MAAM,6BAA6B,CAAC,KAAK,SAAS,MAAM,IAAI,KAAK,GAAG;IACxE;;OAEG;IACH,WAAW,CAAC,EAAE,IAAI,CAAC;IAEnB;;OAEG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B,CAAC;AAKF,MAAM,WAAW,oBAAoB,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM,CAAE,SAAQ,IAAI,CAC/E,cAAc,CAAC,KAAK,EAAE,6BAA6B,CAAC,KAAK,CAAC,CAAC,EAC3D,WAAW,GAAG,aAAa,CAC5B;IACC,SAAS,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IACvG,WAAW,CAAC,WAAW,EAAE,OAAO,CAAC,yBAAyB,CAAC,6BAA6B,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;CAC1G;AAED,MAAM,WAAW,8BAA8B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IAC3E;;;OAGG;IACH,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;IAEjF;;;;;OAKG;IACH,YAAY,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,KAAK,kCAAkC,CAAC,CAAC;IAE9E;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,CAAC,IAAI,EAAE;QACpB,IAAI,EAAE,IAAI,CAAC;QACX,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,CAAC;QAC3C,8EAA8E;QAC9E,GAAG,EAAE,CAAC,KAAK,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;KAChC,KAAK,OAAO,CAAC;CACf;AAED,8FAA8F;AAC9F,MAAM,WAAW,2BAA2B,CAAC,KAAK,SAAS,MAAM,GAAG,MAAM;IACxE;;OAEG;IACH,OAAO,EAAE,oBAAoB,CAAC,KAAK,CAAC,CAAC;IAErC;;;OAGG;IACH,MAAM,EAAE,MAAM,IAAI,CAAC;CACpB;AAID;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,MAAM,EAC3D,OAAO,EAAE,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,EACrC,OAAO,EAAE,CAAC,IAAI,EAAE,6BAA6B,CAAC,KAAK,CAAC,KAAK,IAAI,GAAG,SAAS,EACzE,IAAI,CAAC,EAAE,8BAA8B,CAAC,KAAK,CAAC,GAC3C,2BAA2B,CAAC,KAAK,CAAC,CA0FpC"} |
@@ -23,4 +23,6 @@ type VercelAiOptions = { | ||
| */ | ||
| export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration; | ||
| export declare const vercelAiIntegration: (options?: VercelAiOptions | undefined) => import("@sentry/core").Integration & { | ||
| name: "VercelAI"; | ||
| }; | ||
| export {}; | ||
| //# sourceMappingURL=index.d.ts.map |
@@ -1,1 +0,1 @@ | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/index.ts"],"names":[],"mappings":"AAIA,KAAK,eAAe,GAAG;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAoBF;;GAEG;AACH,eAAO,MAAM,mBAAmB,+EAA0C,CAAC"} | ||
| {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vercel-ai/index.ts"],"names":[],"mappings":"AAIA,KAAK,eAAe,GAAG;IACrB;;;;OAIG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;IAEvB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB;;;OAGG;IACH,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B,CAAC;AAoBF;;GAEG;AACH,eAAO,MAAM,mBAAmB;;CAA0C,CAAC"} |
+3
-3
| { | ||
| "name": "@sentry/server-utils", | ||
| "version": "10.62.0", | ||
| "version": "10.63.0", | ||
| "description": "Server Utilities for all Sentry JavaScript SDKs", | ||
@@ -89,3 +89,3 @@ "repository": "git://github.com/getsentry/sentry-javascript.git", | ||
| "@sentry/conventions": "^0.12.0", | ||
| "@sentry/core": "10.62.0", | ||
| "@sentry/core": "10.63.0", | ||
| "magic-string": "~0.30.0" | ||
@@ -103,3 +103,3 @@ }, | ||
| "build:types:core": "tsc -p tsconfig.types.json", | ||
| "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", | ||
| "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8 && node scripts/inject-ts38-shims.mjs", | ||
| "build:watch": "run-p build:transpile:watch", | ||
@@ -106,0 +106,0 @@ "build:dev:watch": "run-p build:transpile:watch", |
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Debug access
Supply chain riskUses debug, reflection and dynamic code execution features.
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
456369
34.79%134
41.05%3663
44.84%18
50%+ Added
- Removed
Updated