🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

@sentry/server-utils

Package Overview
Dependencies
Maintainers
1
Versions
9
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sentry/server-utils - npm Package Compare versions

Comparing version
10.62.0
to
10.63.0
+42
build/cjs/integrations/tracing-channel/fastify/errors.js
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"}
+6
-2

@@ -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":";;;;;;AAiBA,MAAM,gBAAA,GAAmB,OAAA;AAKzB,MAAM,cAAA,GAAiB,WAAA;AACvB,MAAM,yBAAA,GAA4B,sBAAA;AAClC,MAAM,YAAA,GAAe,SAAA;AACrB,MAAM,YAAA,GAAe,SAAA;AACrB,MAAM,iBAAA,GAAoB,cAAA;AAC1B,MAAM,kBAAA,GAAqB,eAAA;AAC3B,MAAM,kBAAA,GAAqB,eAAA;AA8B3B,MAAM,4BAA4B,MAAM;AACtC,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,gBAAA;AAAA,IACN,SAAA,GAAY;AAEV,MAAA,IAAI,CAAC,mBAAmB,cAAA,EAAgB;AACtC,QAAA;AAAA,MACF;AAEA,MAAA,WAAA,IAAe,KAAA,CAAM,GAAA,CAAI,CAAA,4CAAA,EAA+C,QAAA,CAAS,WAAW,CAAA,CAAA,CAAG,CAAA;AAE/F,MAAA,4BAAA,CAA6B,MAAM;AACjC,QAAA,wBAAA;AAAA,UACE,kBAAA,CAAmB,cAAA,CAAyC,QAAA,CAAS,WAAW,CAAA;AAAA,UAChF,CAAA,IAAA,KAAQ;AACN,YAAA,MAAM,GAAA,GAAM,UAAA,CAAW,IAAA,CAAK,SAAA,CAAU,CAAC,CAAC,CAAA;AACxC,YAAA,MAAM,EAAE,MAAM,IAAA,EAAM,QAAA,EAAU,MAAK,GAAI,mBAAA,CAAoB,KAAK,IAAI,CAAA;AACpE,YAAA,MAAM,aAAa,OAAO,IAAA,KAAS,WAAW,QAAA,CAAS,IAAA,EAAM,EAAE,CAAA,GAAI,IAAA;AACnE,YAAA,MAAM,eAAe,OAAO,UAAA,KAAe,QAAA,IAAY,CAAC,MAAM,UAAU,CAAA;AAIxE,YAAA,IAAA,CAAK,qBAAqB,eAAA,EAAgB;AAE1C,YAAA,OAAO,iBAAA,CAAkB;AAAA,cACvB,MAAM,GAAA,IAAO,aAAA;AAAA,cACb,EAAA,EAAI,IAAA;AAAA,cACJ,UAAA,EAAY;AAAA,gBACV,CAAC,cAAc,GAAG,OAAA;AAAA,gBAClB,CAAC,gCAAgC,GAAG,2BAAA;AAAA,gBACpC,CAAC,yBAAyB,GAAG,aAAA,CAAc,MAAM,YAAA,GAAe,UAAA,GAAa,QAAW,QAAQ,CAAA;AAAA,gBAChG,GAAI,WAAW,EAAE,CAAC,YAAY,GAAG,QAAA,KAAa,EAAC;AAAA,gBAC/C,GAAI,OAAO,EAAE,CAAC,YAAY,GAAG,IAAA,KAAS,EAAC;AAAA,gBACvC,GAAI,MAAM,EAAE,CAAC,iBAAiB,GAAG,GAAA,KAAQ,EAAC;AAAA,gBAC1C,GAAI,OAAO,EAAE,CAAC,kBAAkB,GAAG,IAAA,KAAS,EAAC;AAAA,gBAC7C,GAAI,eAAe,EAAE,CAAC,kBAAkB,GAAG,UAAA,KAAe;AAAC;AAC7D,aACD,CAAA;AAAA,UACH,CAAA;AAAA,UACA;AAAA;AAAA;AAAA,YAGE,YAAA,CAAa,EAAE,IAAA,EAAM,GAAA,EAAI,EAAG;AAC1B,cAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,cAAA,IAAI,CAAC,UAAU,OAAO,MAAA,KAAW,YAAY,CAAC,WAAA,CAAY,MAAM,CAAA,EAAG;AACjE,gBAAA,OAAO,KAAA;AAAA,cACT;AAGA,cAAA,MAAM,cAAc,IAAA,CAAK,kBAAA;AACzB,cAAA,IAAI,WAAA,EAAa;AACf,gBAAA,kBAAA,CAAmB,QAAQ,WAAW,CAAA;AAAA,cACxC;AAEA,cAAA,MAAA,CAAO,EAAA,CAAG,OAAA,EAAS,CAAA,GAAA,KAAO,GAAA,CAAI,GAAG,CAAC,CAAA;AAClC,cAAA,MAAA,CAAO,EAAA,CAAG,KAAA,EAAO,MAAM,GAAA,EAAK,CAAA;AAE5B,cAAA,OAAO,IAAA;AAAA,YACT;AAAA;AACF,SACF;AAAA,MACF,CAAC,CAAA;AAAA,IACH;AAAA,GACF;AACF,CAAA,CAAA;AAEA,SAAS,YAAY,GAAA,EAA2F;AAC9G,EAAA,OAAO,IAAA,IAAQ,GAAA,IAAO,OAAQ,GAAA,CAAyB,EAAA,KAAO,UAAA;AAChE;AAEA,SAAS,WAAW,QAAA,EAAuC;AACzD,EAAA,IAAI,OAAO,aAAa,QAAA,EAAU;AAChC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,IAAI,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,IAAY,SAAS,QAAA,EAAU;AACjE,IAAA,MAAM,MAAO,QAAA,CAA+B,GAAA;AAC5C,IAAA,OAAO,OAAO,GAAA,KAAQ,QAAA,GAAW,GAAA,GAAM,MAAA;AAAA,EACzC;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,oBAAoB,UAAA,EAK3B;AAGA,EAAA,MAAM,SAAS,UAAA,EAAY,MAAA,EAAQ,gBAAA,IAAoB,UAAA,EAAY,UAAU,EAAC;AAC9E,EAAA,OAAO;AAAA,IACL,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,MAAM,MAAA,CAAO,IAAA;AAAA,IACb,UAAU,MAAA,CAAO,QAAA;AAAA,IACjB,MAAM,MAAA,CAAO;AAAA,GACf;AACF;AAEA,SAAS,aAAA,CAAc,IAAA,EAA0B,IAAA,EAA0B,QAAA,EAAsC;AAC/G,EAAA,IAAI,CAAA,GAAI,CAAA,aAAA,EAAgB,IAAA,IAAQ,WAAW,CAAA,CAAA;AAC3C,EAAA,IAAI,OAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,CAAA,IAAK,IAAI,IAAI,CAAA,CAAA;AAAA,EACf;AACA,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,CAAA,IAAK,IAAI,QAAQ,CAAA,CAAA;AAAA,EACnB;AACA,EAAA,OAAO,CAAA;AACT;AAUO,MAAM,uBAAA,GAA0B,kBAAkB,wBAAwB;;;;"}
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":";;;AAmDA,MAAM,OAAO,MAAY;AAAC,CAAA;AAWnB,SAAS,wBAAA,CACd,OAAA,EACA,OAAA,EACA,IAAA,EACoC;AACpC,EAAA,MAAM,MAAA,GAAS,sBAAA,CAAuB,OAAA,EAAS,OAAO,CAAA;AAEtD,EAAA,MAAM,gBAAgB,IAAA,EAAM,aAAA;AAC5B,EAAA,MAAM,YAAA,GAAe,CAAC,CAAA,KAAmD;AACvE,IAAA,IAAI,OAAO,IAAA,EAAM,YAAA,KAAiB,UAAA,EAAY;AAC5C,MAAA,OAAO,IAAA,CAAK,aAAa,CAAC,CAAA;AAAA,IAC5B;AAEA,IAAA,OAAO;AAAA,MACL,SAAA,EAAW;AAAA,QACT,IAAA,EAAM,oCAAA;AAAA,QACN,OAAA,EAAS;AAAA;AACX,KACF;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,WAAA,GAAwF;AAAA,IAC5F,KAAA,EAAO,IAAA;AAAA,IACP,UAAA,EAAY,IAAA;AAAA,IACZ,IAAI,IAAA,EAAM;AAGR,MAAA,IAAI,OAAA,IAAW,IAAA,IAAQ,QAAA,IAAY,IAAA,EAAM;AACvC,QAAA,YAAA,CAAa,MAAM,aAAa,CAAA;AAAA,MAClC;AAAA,IACF,CAAA;AAAA,IACA,MAAM,IAAA,EAAM;AAGV,MAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,MAAA,IAAI,CAAC,IAAA,EAAM;AACT,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,MAAM,YAAA,EAAc;AACtB,QAAA,gBAAA,CAAiB,IAAA,CAAK,KAAA,EAAO,YAAA,CAAa,IAAA,CAAK,KAAK,CAAC,CAAA;AAAA,MACvD;AAEA,MAAA,IAAA,CAAK,SAAA,CAAU,EAAE,IAAA,EAAM,iBAAA,EAAmB,SAAS,eAAA,CAAgB,IAAA,CAAK,KAAK,CAAA,EAAG,CAAA;AAAA,IAClF,CAAA;AAAA,IACA,SAAS,IAAA,EAAM;AACb,MAAA,YAAA,CAAa,MAAM,aAAa,CAAA;AAAA,IAClC;AAAA,GACF;AAEA,EAAA,MAAA,CAAO,OAAA,CAAQ,UAAU,WAAW,CAAA;AAEpC,EAAA,OAAO;AAAA,IACL,SAAS,MAAA,CAAO,OAAA;AAAA,IAChB,QAAQ,MAAM;AACZ,MAAA,MAAA,CAAO,OAAA,CAAQ,YAAY,WAAW,CAAA;AACtC,MAAA,MAAA,CAAO,MAAA,EAAO;AAAA,IAChB;AAAA,GACF;AACF;AASA,SAAS,sBAAA,CACP,SACA,OAAA,EACoC;AAEpC,EAAA,MAAM,UAAU,kCAAA,EAAmC;AAInD,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,WAAA,IAAe,KAAA,CAAM,IAAI,0DAA0D,CAAA;AAEnF,IAAA,OAAO;AAAA,MACL,OAAA;AAAA,MACA,MAAA,EAAQ;AAAA,KACV;AAAA,EACF;AAGA,EAAA,MAAM,oBAAoB,OAAA,CAAQ,iBAAA;AAOlC,EAAA,OAAA,CAAQ,KAAA,CAAM,SAAA,CAAU,iBAAA,EAAmB,CAAC,IAAA,KAA+C;AACzF,IAAA,MAAM,IAAA,GAAO,QAAQ,IAAI,CAAA;AACzB,IAAA,IAAI,CAAC,IAAA,EAAM;AAET,MAAA,OAAO,kBAAkB,QAAA,EAAS;AAAA,IACpC;AACA,IAAA,IAAA,CAAK,WAAA,GAAc,IAAA;AAEnB,IAAA,OAAO,OAAA,CAAQ,uBAAuB,IAAI,CAAA;AAAA,EAC5C,CAAC,CAAA;AAED,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,QAAQ,MAAM;AAEZ,MAAA,OAAA,CAAQ,KAAA,CAAM,YAAY,iBAAiB,CAAA;AAAA,IAC7C;AAAA,GACF;AACF;AAEA,SAAS,YAAA,CACP,MACA,aAAA,EACM;AACN,EAAA,MAAM,OAAO,IAAA,CAAK,WAAA;AAClB,EAAA,IAAI,CAAC,IAAA,EAAM;AACT,IAAA;AAAA,EACF;AACA,EAAA,aAAA,GAAgB,MAAM,IAAI,CAAA;AAC1B,EAAA,IAAA,CAAK,GAAA,EAAI;AACX;AAGA,SAAS,gBAAgB,KAAA,EAAwB;AAC/C,EAAA,IAAI,KAAA,IAAS,OAAO,KAAA,KAAU,QAAA,IAAY,aAAa,KAAA,IAAS,OAAO,KAAA,CAAM,OAAA,KAAY,QAAA,EAAU;AACjG,IAAA,OAAO,KAAA,CAAM,OAAA;AAAA,EACf;AACA,EAAA,OAAO,OAAO,KAAK,CAAA;AACrB;;;;"}
{"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"}
{
"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",