From ea7f099e8d26880506d47b967f116126a4cf9303 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Wed, 5 Aug 2026 00:30:44 +0100 Subject: [PATCH] chore(server-utils): Simplify `injectChannelSubscribers` --- .../server-utils/src/orchestrion/apmTypes.ts | 4 + .../src/orchestrion/bundler/options.ts | 13 +-- .../orchestrion/bundler/subscribeInjection.ts | 46 ++++---- .../src/orchestrion/config/amqplib.ts | 4 +- .../src/orchestrion/config/anthropic-ai.ts | 4 +- .../src/orchestrion/config/aws-sdk.ts | 4 +- .../src/orchestrion/config/dataloader.ts | 3 - .../src/orchestrion/config/express.ts | 4 +- .../src/orchestrion/config/firebase.ts | 4 +- .../src/orchestrion/config/generic-pool.ts | 4 +- .../src/orchestrion/config/google-genai.ts | 4 +- .../src/orchestrion/config/graphql.ts | 4 +- .../src/orchestrion/config/hapi.ts | 4 +- .../src/orchestrion/config/index.ts | 101 +++++------------- .../src/orchestrion/config/ioredis.ts | 4 +- .../src/orchestrion/config/kafkajs.ts | 4 +- .../src/orchestrion/config/knex.ts | 3 - .../src/orchestrion/config/koa.ts | 4 +- .../src/orchestrion/config/langchain.ts | 4 +- .../src/orchestrion/config/langgraph.ts | 4 +- .../src/orchestrion/config/lru-memoizer.ts | 4 +- .../src/orchestrion/config/module-names.ts | 10 ++ .../src/orchestrion/config/mongodb.ts | 4 +- .../src/orchestrion/config/mongoose.ts | 4 +- .../src/orchestrion/config/mysql.ts | 4 +- .../src/orchestrion/config/mysql2.ts | 4 +- .../src/orchestrion/config/nestjs.ts | 3 - .../src/orchestrion/config/openai.ts | 4 +- .../server-utils/src/orchestrion/config/pg.ts | 4 +- .../src/orchestrion/config/postgres.ts | 4 +- .../src/orchestrion/config/redis.ts | 4 +- .../src/orchestrion/config/remix.ts | 3 - .../orchestrion/config/subscribe-injection.ts | 63 ----------- .../src/orchestrion/config/tedious.ts | 4 +- .../src/orchestrion/config/vercel-ai.ts | 4 +- .../test/orchestrion/config.test.ts | 20 ++-- .../orchestrion/subscribeInjection.test.ts | 8 +- yarn.lock | 6 +- 38 files changed, 117 insertions(+), 266 deletions(-) create mode 100644 packages/server-utils/src/orchestrion/config/module-names.ts delete mode 100644 packages/server-utils/src/orchestrion/config/subscribe-injection.ts diff --git a/packages/server-utils/src/orchestrion/apmTypes.ts b/packages/server-utils/src/orchestrion/apmTypes.ts index 0df0a57d9069..8883545900f7 100644 --- a/packages/server-utils/src/orchestrion/apmTypes.ts +++ b/packages/server-utils/src/orchestrion/apmTypes.ts @@ -148,6 +148,10 @@ export interface CodeTransformerPluginOptions { * * A single transform can serve many configs — each invocation can branch on * `state.module.name` or `state.channelName` to tell the sites apart. + * + * An entry named after a built-in transform (e.g. `tracingChannelImport`) overrides it wherever + * the transformer dispatches it, including internal calls; the originals stay reachable on + * `state.transforms.defaults` so an override can chain the default behaviour. */ customTransforms?: Record; /** diff --git a/packages/server-utils/src/orchestrion/bundler/options.ts b/packages/server-utils/src/orchestrion/bundler/options.ts index 8e2d0db8373f..c348c1f18056 100644 --- a/packages/server-utils/src/orchestrion/bundler/options.ts +++ b/packages/server-utils/src/orchestrion/bundler/options.ts @@ -82,14 +82,11 @@ export function externalizedModulesWarning(externalizedModules: string[]): strin * visible to the runtime). */ export function orchestrionTransformOptions(options: PluginOptions): CodeTransformerPluginOptions { - const subscribeInjection = options.injectChannelSubscribers ? subscribeInjectionOptions() : undefined; - - const instrumentations = [ - ...SENTRY_INSTRUMENTATIONS, - ...(options.instrumentations || []), - ...(subscribeInjection?.instrumentations || []), - ]; - const customTransforms = { ...options.customTransforms, ...subscribeInjection?.customTransforms }; + const instrumentations = [...SENTRY_INSTRUMENTATIONS, ...(options.instrumentations || [])]; + const customTransforms = { + ...options.customTransforms, + ...(options.injectChannelSubscribers ? subscribeInjectionOptions().customTransforms : undefined), + }; if (options.shouldInjectDiagnostics === false) { return { diff --git a/packages/server-utils/src/orchestrion/bundler/subscribeInjection.ts b/packages/server-utils/src/orchestrion/bundler/subscribeInjection.ts index b60562575915..2d0022aad107 100644 --- a/packages/server-utils/src/orchestrion/bundler/subscribeInjection.ts +++ b/packages/server-utils/src/orchestrion/bundler/subscribeInjection.ts @@ -1,8 +1,6 @@ import type { CustomTransform } from '../apmTypes'; import { parse } from 'meriyah'; -import { SUBSCRIBE_INJECTIONS } from '../config'; import { subscriberExportForModule } from '../config/channel-integration-definitions'; -import { SUBSCRIBE_TRANSFORM_NAME } from '../config/subscribe-injection'; import type { PluginOptions } from './options'; // Tracks Program nodes we already injected into, so a package with several @@ -38,22 +36,33 @@ function subscribeSnippet(exportName: string, esm: boolean): string { } /** - * The custom transform registered under {@link SUBSCRIBE_TRANSFORM_NAME}. It is - * invoked with the matched `Program` node and mutates it in place, splicing the - * marker-push snippet in after any `'use strict'` directive. + * Override for orchestrion's built-in `tracingChannelImport` transform, which + * runs (via `tracingChannelDeclaration`) for every file that gets a channel + * wrapped — the one hook that reaches every instrumented module without any + * extra instrumentation configs. It chains the default (which splices the + * `diagnostics_channel` import and bails when it is already present), then + * splices the marker-push snippet in after any `'use strict'` directive. * - * `state` carries the matched config spread with `{ moduleType }`; the config's - * `channelName` carries the package name (see `toSubscribeInjections`), which - * maps to the subscriber's export name. + * Invoked once per wrapped channel, so the `WeakSet` keeps the snippet to one + * per file. Requires `@apm-js-collab/code-transformer` >= 0.18.1, where + * built-ins dispatch through the override map and expose the originals on + * `state.transforms.defaults`. */ -const injectSubscribe: CustomTransform = (state, program) => { +const injectSubscribe: CustomTransform = (state, program, parent, ancestry) => { + const { moduleType, module, transforms } = state as { + moduleType?: string; + module?: { name?: string }; + transforms: { defaults: { tracingChannelImport: CustomTransform } }; + }; + + transforms.defaults.tracingChannelImport(state, program, parent, ancestry); + const node = program as ProgramNode; if (injectedPrograms.has(node)) { return; } - const { moduleType, channelName } = state as { moduleType?: string; channelName?: string }; - const exportName = channelName ? subscriberExportForModule(channelName) : undefined; + const exportName = module?.name ? subscriberExportForModule(module.name) : undefined; if (!exportName) { return; } @@ -70,18 +79,17 @@ const injectSubscribe: CustomTransform = (state, program) => { }; /** - * The `instrumentations` + `customTransforms` a bundler plugin passes to + * The `customTransforms` a bundler plugin passes to * {@link orchestrionTransformOptions} to enable the marker-push subscribe * injection used by bundler-only SDKs (e.g. `@sentry/cloudflare`). * - * The `SUBSCRIBE_INJECTIONS` configs ride alongside the real channel-publishing - * configs, and `injectSubscribe` runs on each matched module, so every - * transformed package self-registers its subscriber on the global marker - * without a runtime module hook. + * Overriding the built-in `tracingChannelImport` transform makes + * `injectSubscribe` run on every instrumented module, so every transformed + * package self-registers its subscriber on the global marker without a runtime + * module hook — and without a parallel set of injection configs. */ -export function subscribeInjectionOptions(): Pick { +export function subscribeInjectionOptions(): Pick { return { - instrumentations: SUBSCRIBE_INJECTIONS, - customTransforms: { [SUBSCRIBE_TRANSFORM_NAME]: injectSubscribe }, + customTransforms: { tracingChannelImport: injectSubscribe }, }; } diff --git a/packages/server-utils/src/orchestrion/config/amqplib.ts b/packages/server-utils/src/orchestrion/config/amqplib.ts index 5a74e81e66d1..769a68ab420e 100644 --- a/packages/server-utils/src/orchestrion/config/amqplib.ts +++ b/packages/server-utils/src/orchestrion/config/amqplib.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // `amqplib` splits its API across three files: // - `lib/channel_model.js` holds `class Channel` (publish/consume/ack/nack/reject/…) and @@ -90,5 +90,3 @@ export const amqplibChannels = { AMQPLIB_NACK_ALL: 'orchestrion:amqplib:nackAll', AMQPLIB_CONNECT: 'orchestrion:amqplib:connect', } as const; - -export const amqplibSubscribeInjection = toSubscribeInjections(amqplibConfig); diff --git a/packages/server-utils/src/orchestrion/config/anthropic-ai.ts b/packages/server-utils/src/orchestrion/config/anthropic-ai.ts index 10ce95629fa8..b16924c40687 100644 --- a/packages/server-utils/src/orchestrion/config/anthropic-ai.ts +++ b/packages/server-utils/src/orchestrion/config/anthropic-ai.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const anthropicAiConfig = [ // One entry each for CJS/ESM @@ -41,5 +41,3 @@ export const anthropicAiChannels = { ANTHROPIC_MODELS: 'orchestrion:@anthropic-ai/sdk:models', ANTHROPIC_MESSAGES_STREAM: 'orchestrion:@anthropic-ai/sdk:messages-stream', } as const; - -export const anthropicAiSubscribeInjection = toSubscribeInjections(anthropicAiConfig); diff --git a/packages/server-utils/src/orchestrion/config/aws-sdk.ts b/packages/server-utils/src/orchestrion/config/aws-sdk.ts index f7a80d6f7eeb..240fa0074194 100644 --- a/packages/server-utils/src/orchestrion/config/aws-sdk.ts +++ b/packages/server-utils/src/orchestrion/config/aws-sdk.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '../apmTypes'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // The AWS SDK (v3) routes every command through the smithy `Client.prototype.send` method. Which // package hosts that `Client` class changed across versions, so we target all of them; only the one @@ -35,5 +35,3 @@ export const awsSdkChannels = { AWS_SMITHY_CLIENT_SEND: 'orchestrion:@smithy/smithy-client:send', AWS_SDK_SMITHY_CLIENT_SEND: 'orchestrion:@aws-sdk/smithy-client:send', } as const; - -export const awsSdkSubscribeInjection = toSubscribeInjections(awsSdkConfig); diff --git a/packages/server-utils/src/orchestrion/config/dataloader.ts b/packages/server-utils/src/orchestrion/config/dataloader.ts index 58cc3b7ba621..cd1f0879bdc3 100644 --- a/packages/server-utils/src/orchestrion/config/dataloader.ts +++ b/packages/server-utils/src/orchestrion/config/dataloader.ts @@ -1,5 +1,4 @@ import type { InstrumentationConfig } from '..'; -import { toSubscribeInjections } from './subscribe-injection'; // `dataloader` ships a single transpiled CommonJS `index.js`. Its class methods are emitted as // `_proto. = function () {}` (named function *expressions*), so they match on @@ -54,5 +53,3 @@ export const dataloaderChannels = { DATALOADER_CLEAR: 'orchestrion:dataloader:clear', DATALOADER_CLEAR_ALL: 'orchestrion:dataloader:clearAll', } as const; - -export const dataloaderSubscribeInjection = toSubscribeInjections(dataloaderConfig); diff --git a/packages/server-utils/src/orchestrion/config/express.ts b/packages/server-utils/src/orchestrion/config/express.ts index c86fcada8ea1..0e1c0aa86dc7 100644 --- a/packages/server-utils/src/orchestrion/config/express.ts +++ b/packages/server-utils/src/orchestrion/config/express.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const expressConfig = [ // Express funnels every middleware/route handler through a single method on @@ -75,5 +75,3 @@ export const expressChannels = { EXPRESS_REGISTER: 'orchestrion:express:register', ROUTER_REGISTER: 'orchestrion:router:register', } as const; - -export const expressSubscribeInjection = toSubscribeInjections(expressConfig); diff --git a/packages/server-utils/src/orchestrion/config/firebase.ts b/packages/server-utils/src/orchestrion/config/firebase.ts index 1a0b42eb20d4..6787ccd171d3 100644 --- a/packages/server-utils/src/orchestrion/config/firebase.ts +++ b/packages/server-utils/src/orchestrion/config/firebase.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // firebase 9+ ships firestore as `@firebase/firestore` (matches the OTel integration's range). Only the // `lite` SDK exposes the free `addDoc`/`getDocs`/`setDoc`/`deleteDoc` functions we trace, and only the @@ -93,5 +93,3 @@ export const firebaseChannels = { FIREBASE_FUNCTIONS_STORAGE_DELETED: 'orchestrion:firebase-functions:storage-deleted', FIREBASE_FUNCTIONS_STORAGE_METADATA_UPDATED: 'orchestrion:firebase-functions:storage-metadata-updated', } as const; - -export const firebaseSubscribeInjection = toSubscribeInjections(firebaseConfig); diff --git a/packages/server-utils/src/orchestrion/config/generic-pool.ts b/packages/server-utils/src/orchestrion/config/generic-pool.ts index 4f02340af582..d05ee3df0092 100644 --- a/packages/server-utils/src/orchestrion/config/generic-pool.ts +++ b/packages/server-utils/src/orchestrion/config/generic-pool.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // Two shapes of `acquire`, both publishing to the same `orchestrion:generic-pool:acquire` channel: // - v3+: `class Pool { acquire(priority) }` returns a promise, so `kind: 'Auto'` resolves to `wrapPromise`. @@ -24,5 +24,3 @@ export const genericPoolModuleNames = getModuleNames(genericPoolConfig); export const genericPoolChannels = { GENERIC_POOL_ACQUIRE: 'orchestrion:generic-pool:acquire', } as const; - -export const genericPoolSubscribeInjection = toSubscribeInjections(genericPoolConfig); diff --git a/packages/server-utils/src/orchestrion/config/google-genai.ts b/packages/server-utils/src/orchestrion/config/google-genai.ts index 666dc06afd00..4be83b0d7e50 100644 --- a/packages/server-utils/src/orchestrion/config/google-genai.ts +++ b/packages/server-utils/src/orchestrion/config/google-genai.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // `@google/genai` ships one bundled file per module format and the matcher compares `filePath` exactly, // so we list every file the `node` export condition resolves to across the supported range: `index.js` @@ -41,5 +41,3 @@ export const googleGenAiChannels = { GOOGLE_GENAI_EMBED_CONTENT: 'orchestrion:@google/genai:embed-content', GOOGLE_GENAI_CHAT: 'orchestrion:@google/genai:chat', } as const; - -export const googleGenAiSubscribeInjection = toSubscribeInjections(googleGenAiConfig); diff --git a/packages/server-utils/src/orchestrion/config/graphql.ts b/packages/server-utils/src/orchestrion/config/graphql.ts index f8390e0133db..07e509b5a313 100644 --- a/packages/server-utils/src/orchestrion/config/graphql.ts +++ b/packages/server-utils/src/orchestrion/config/graphql.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // `parse`/`validate`/`execute` are top-level named `function` declarations in graphql's compiled // files, stable across the supported majors, so `functionName` matches. `execute` returns @@ -29,5 +29,3 @@ export const graphqlChannels = { } as const; export const graphqlModuleNames = getModuleNames(graphqlConfig); - -export const graphqlSubscribeInjection = toSubscribeInjections(graphqlConfig); diff --git a/packages/server-utils/src/orchestrion/config/hapi.ts b/packages/server-utils/src/orchestrion/config/hapi.ts index ba06bc86e4f4..90b8bde0085c 100644 --- a/packages/server-utils/src/orchestrion/config/hapi.ts +++ b/packages/server-utils/src/orchestrion/config/hapi.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const hapiConfig = [ // hapi's `route`/`ext` live on an anonymous class (`internals.Server = class {}`), @@ -24,5 +24,3 @@ export const hapiChannels = { HAPI_ROUTE: 'orchestrion:@hapi/hapi:route', HAPI_EXT: 'orchestrion:@hapi/hapi:ext', } as const; - -export const hapiSubscribeInjection = toSubscribeInjections(hapiConfig); diff --git a/packages/server-utils/src/orchestrion/config/index.ts b/packages/server-utils/src/orchestrion/config/index.ts index cc0522ac6b4e..7d43cd6c60ed 100644 --- a/packages/server-utils/src/orchestrion/config/index.ts +++ b/packages/server-utils/src/orchestrion/config/index.ts @@ -1,35 +1,35 @@ import type { InstrumentationConfig } from '..'; import { uniq } from '@sentry/core'; -import { awsSdkConfig, awsSdkSubscribeInjection } from './aws-sdk'; -import { amqplibConfig, amqplibSubscribeInjection } from './amqplib'; -import { anthropicAiConfig, anthropicAiSubscribeInjection } from './anthropic-ai'; -import { dataloaderConfig, dataloaderSubscribeInjection } from './dataloader'; -import { expressConfig, expressSubscribeInjection } from './express'; -import { firebaseConfig, firebaseSubscribeInjection } from './firebase'; -import { genericPoolConfig, genericPoolSubscribeInjection } from './generic-pool'; -import { googleGenAiConfig, googleGenAiSubscribeInjection } from './google-genai'; -import { graphqlConfig, graphqlSubscribeInjection } from './graphql'; -import { hapiConfig, hapiSubscribeInjection } from './hapi'; -import { ioredisConfig, ioredisSubscribeInjection } from './ioredis'; -import { kafkajsConfig, kafkajsSubscribeInjection } from './kafkajs'; -import { knexConfig, knexSubscribeInjection } from './knex'; -import { koaConfig, koaSubscribeInjection } from './koa'; -import { langchainConfig, langchainSubscribeInjection } from './langchain'; -import { langgraphConfig, langgraphSubscribeInjection } from './langgraph'; -import { lruMemoizerConfig, lruMemoizerSubscribeInjection } from './lru-memoizer'; -import { mongodbConfig, mongodbSubscribeInjection } from './mongodb'; -import { mongooseConfig, mongooseSubscribeInjection } from './mongoose'; -import { mysql2Config, mysql2SubscribeInjection } from './mysql2'; -import { mysqlConfig, mysqlSubscribeInjection } from './mysql'; -import { nestjsConfig, nestjsSubscribeInjection } from './nestjs'; -import { openaiConfig, openaiSubscribeInjection } from './openai'; -import { pgConfig, pgSubscribeInjection } from './pg'; -import { postgresJsConfig, postgresJsSubscribeInjection } from './postgres'; -import { redisConfig, redisSubscribeInjection } from './redis'; -import { remixConfig, remixSubscribeInjection } from './remix'; -import { tediousConfig, tediousSubscribeInjection } from './tedious'; -import { vercelAiConfig, vercelAiSubscribeInjection } from './vercel-ai'; +import { awsSdkConfig } from './aws-sdk'; +import { amqplibConfig } from './amqplib'; +import { anthropicAiConfig } from './anthropic-ai'; +import { dataloaderConfig } from './dataloader'; +import { expressConfig } from './express'; +import { firebaseConfig } from './firebase'; +import { genericPoolConfig } from './generic-pool'; +import { googleGenAiConfig } from './google-genai'; +import { graphqlConfig } from './graphql'; +import { hapiConfig } from './hapi'; +import { ioredisConfig } from './ioredis'; +import { kafkajsConfig } from './kafkajs'; +import { knexConfig } from './knex'; +import { koaConfig } from './koa'; +import { langchainConfig } from './langchain'; +import { langgraphConfig } from './langgraph'; +import { lruMemoizerConfig } from './lru-memoizer'; +import { mongodbConfig } from './mongodb'; +import { mongooseConfig } from './mongoose'; +import { mysql2Config } from './mysql2'; +import { mysqlConfig } from './mysql'; +import { nestjsConfig } from './nestjs'; +import { openaiConfig } from './openai'; +import { pgConfig } from './pg'; +import { postgresJsConfig } from './postgres'; +import { redisConfig } from './redis'; +import { remixConfig } from './remix'; +import { tediousConfig } from './tedious'; +import { vercelAiConfig } from './vercel-ai'; // Kept sorted alphabetically by module so concurrent additions insert at different // points rather than all appending to the end (fewer merge conflicts). @@ -72,49 +72,6 @@ export const SENTRY_INSTRUMENTATIONS: InstrumentationConfig[] = [ ...vercelAiConfig, ]; -/** - * The `Program`-matching injection configs that make each instrumented file - * self-register its channel subscriber at load (used by bundler-only SDKs like - * `@sentry/cloudflare`). - * - * Deliberately separate from `SENTRY_INSTRUMENTATIONS`: these reference a custom - * transform that only the opted-in bundler plugin registers, so feeding them to - * the runtime `--import` hook (which can't register it) would make the - * code-transformer drop the whole file. Each library owns its own - * `*SubscribeInjection` (derived from its channel configs), collected here. - */ -export const SUBSCRIBE_INJECTIONS: InstrumentationConfig[] = [ - ...amqplibSubscribeInjection, - ...anthropicAiSubscribeInjection, - ...awsSdkSubscribeInjection, - ...dataloaderSubscribeInjection, - ...expressSubscribeInjection, - ...firebaseSubscribeInjection, - ...genericPoolSubscribeInjection, - ...googleGenAiSubscribeInjection, - ...graphqlSubscribeInjection, - ...hapiSubscribeInjection, - ...ioredisSubscribeInjection, - ...kafkajsSubscribeInjection, - ...knexSubscribeInjection, - ...koaSubscribeInjection, - ...langchainSubscribeInjection, - ...langgraphSubscribeInjection, - ...lruMemoizerSubscribeInjection, - ...mongodbSubscribeInjection, - ...mongooseSubscribeInjection, - ...mysql2SubscribeInjection, - ...mysqlSubscribeInjection, - ...nestjsSubscribeInjection, - ...openaiSubscribeInjection, - ...pgSubscribeInjection, - ...postgresJsSubscribeInjection, - ...redisSubscribeInjection, - ...remixSubscribeInjection, - ...tediousSubscribeInjection, - ...vercelAiSubscribeInjection, -]; - /** * The unique set of package names instrumented by `SENTRY_INSTRUMENTATIONS` * merged with any caller-provided `instrumentations` (e.g. `['mysql']`). diff --git a/packages/server-utils/src/orchestrion/config/ioredis.ts b/packages/server-utils/src/orchestrion/config/ioredis.ts index 3aa4c014cd00..edaa7f525985 100644 --- a/packages/server-utils/src/orchestrion/config/ioredis.ts +++ b/packages/server-utils/src/orchestrion/config/ioredis.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const ioredisConfig = [ // ioredis `<5.11.0` (>=5.11.0 publishes its own `ioredis:*` diagnostics_channel) @@ -33,5 +33,3 @@ export const ioredisChannels = { IOREDIS_COMMAND: 'orchestrion:ioredis:command', IOREDIS_CONNECT: 'orchestrion:ioredis:connect', } as const; - -export const ioredisSubscribeInjection = toSubscribeInjections(ioredisConfig); diff --git a/packages/server-utils/src/orchestrion/config/kafkajs.ts b/packages/server-utils/src/orchestrion/config/kafkajs.ts index acb593cb0043..56429345f8f6 100644 --- a/packages/server-utils/src/orchestrion/config/kafkajs.ts +++ b/packages/server-utils/src/orchestrion/config/kafkajs.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const kafkajsConfig = [ { @@ -28,5 +28,3 @@ export const kafkajsChannels = { KAFKAJS_SEND_BATCH: 'orchestrion:kafkajs:send_batch', KAFKAJS_CONSUMER_RUN: 'orchestrion:kafkajs:consumer_run', } as const; - -export const kafkajsSubscribeInjection = toSubscribeInjections(kafkajsConfig); diff --git a/packages/server-utils/src/orchestrion/config/knex.ts b/packages/server-utils/src/orchestrion/config/knex.ts index aa407c5fc198..8c4c2d068563 100644 --- a/packages/server-utils/src/orchestrion/config/knex.ts +++ b/packages/server-utils/src/orchestrion/config/knex.ts @@ -1,5 +1,4 @@ import type { InstrumentationConfig } from '..'; -import { toSubscribeInjections } from './subscribe-injection'; const MODULE_NAME = 'knex'; @@ -52,5 +51,3 @@ export const knexChannels = { KNEX_SCHEMA_BUILDER: 'orchestrion:knex:schemaBuilder', KNEX_RAW: 'orchestrion:knex:raw', } as const; - -export const knexSubscribeInjection = toSubscribeInjections(knexConfig); diff --git a/packages/server-utils/src/orchestrion/config/koa.ts b/packages/server-utils/src/orchestrion/config/koa.ts index a12ef52e0b72..932983a04ca3 100644 --- a/packages/server-utils/src/orchestrion/config/koa.ts +++ b/packages/server-utils/src/orchestrion/config/koa.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '../apmTypes'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const koaConfig = [ { @@ -14,5 +14,3 @@ export const koaModuleNames = getModuleNames(koaConfig); export const koaChannels = { KOA_USE: 'orchestrion:koa:use', } as const; - -export const koaSubscribeInjection = toSubscribeInjections(koaConfig); diff --git a/packages/server-utils/src/orchestrion/config/langchain.ts b/packages/server-utils/src/orchestrion/config/langchain.ts index 43a311d868e3..8d6df2950b5e 100644 --- a/packages/server-utils/src/orchestrion/config/langchain.ts +++ b/packages/server-utils/src/orchestrion/config/langchain.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // `@langchain/*` packages ship dual CJS/ESM builds (`.cjs` for `require`, `.js` for `import`) and the // matcher compares `filePath` exactly, so each hook is declared once per built file. @@ -74,5 +74,3 @@ export const langchainChannels = { LANGCHAIN_CHAT_MODEL_INVOKE: 'orchestrion:@langchain/core:chatModelInvoke', LANGCHAIN_CHAT_MODEL_STREAM: 'orchestrion:@langchain/core:chatModelStream', } as const; - -export const langchainSubscribeInjection = toSubscribeInjections(langchainConfig); diff --git a/packages/server-utils/src/orchestrion/config/langgraph.ts b/packages/server-utils/src/orchestrion/config/langgraph.ts index 060a18943d1d..9c66745ddb36 100644 --- a/packages/server-utils/src/orchestrion/config/langgraph.ts +++ b/packages/server-utils/src/orchestrion/config/langgraph.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // `@langchain/langgraph` ships dual CJS/ESM builds (`.cjs` for `require`, `.js` for `import`) and the // matcher compares `filePath` exactly, so each hook is declared once per built file. `StateGraph.compile` @@ -35,5 +35,3 @@ export const langgraphChannels = { LANGGRAPH_STATE_GRAPH_COMPILE: 'orchestrion:@langchain/langgraph:stateGraphCompile', LANGGRAPH_CREATE_REACT_AGENT: 'orchestrion:@langchain/langgraph:createReactAgent', } as const; - -export const langgraphSubscribeInjection = toSubscribeInjections(langgraphConfig); diff --git a/packages/server-utils/src/orchestrion/config/lru-memoizer.ts b/packages/server-utils/src/orchestrion/config/lru-memoizer.ts index 2806a3a2e9d2..b0cf7f37bca8 100644 --- a/packages/server-utils/src/orchestrion/config/lru-memoizer.ts +++ b/packages/server-utils/src/orchestrion/config/lru-memoizer.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const lruMemoizerConfig = [ { @@ -15,5 +15,3 @@ export const lruMemoizerModuleNames = getModuleNames(lruMemoizerConfig); export const lruMemoizerChannels = { LRU_MEMOIZER_LOAD: 'orchestrion:lru-memoizer:load', } as const; - -export const lruMemoizerSubscribeInjection = toSubscribeInjections(lruMemoizerConfig); diff --git a/packages/server-utils/src/orchestrion/config/module-names.ts b/packages/server-utils/src/orchestrion/config/module-names.ts new file mode 100644 index 000000000000..d19cdbe75867 --- /dev/null +++ b/packages/server-utils/src/orchestrion/config/module-names.ts @@ -0,0 +1,10 @@ +import type { InstrumentationConfig } from '../apmTypes'; + +/** + * The distinct instrumented package names (`module.name`) across a library's + * channel configs. Integrations pass this to `invokeOrchestrionInstrumentation` + * so they subscribe only once one of their packages is actually injected. + */ +export function getModuleNames(configs: readonly InstrumentationConfig[]): string[] { + return [...new Set(configs.map(config => config.module.name))]; +} diff --git a/packages/server-utils/src/orchestrion/config/mongodb.ts b/packages/server-utils/src/orchestrion/config/mongodb.ts index c1a9c27ea329..6d5816c07475 100644 --- a/packages/server-utils/src/orchestrion/config/mongodb.ts +++ b/packages/server-utils/src/orchestrion/config/mongodb.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // The mongodb driver's command architecture changed across majors, mirrored in the vendored OTel // instrumentation's version bands: @@ -73,5 +73,3 @@ export const mongodbChannels = { MONGODB_V3_QUERY: 'orchestrion:mongodb:v3_query', MONGODB_V3_GET_MORE: 'orchestrion:mongodb:v3_get_more', } as const; - -export const mongodbSubscribeInjection = toSubscribeInjections(mongodbConfig); diff --git a/packages/server-utils/src/orchestrion/config/mongoose.ts b/packages/server-utils/src/orchestrion/config/mongoose.ts index b1bbea4a2dfb..2a9c8c1ee4eb 100644 --- a/packages/server-utils/src/orchestrion/config/mongoose.ts +++ b/packages/server-utils/src/orchestrion/config/mongoose.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // mongoose >= 9.7.0 publishes via its own `node:diagnostics_channel` tracing channels (handled by // `subscribeMongooseDiagnosticChannels`), so this transform is gated to `< 9.7.0` to avoid emitting @@ -127,5 +127,3 @@ export const mongooseChannels = { export const MONGOOSE_CONTEXT_CAPTURE_CHANNELS: string[] = CONTEXT_CAPTURE_QUERY_METHODS.map( methodName => `orchestrion:mongoose:ctx_${methodName}`, ); - -export const mongooseSubscribeInjection = toSubscribeInjections(mongooseConfig); diff --git a/packages/server-utils/src/orchestrion/config/mysql.ts b/packages/server-utils/src/orchestrion/config/mysql.ts index b77f3f1ac10f..982619eadb1e 100644 --- a/packages/server-utils/src/orchestrion/config/mysql.ts +++ b/packages/server-utils/src/orchestrion/config/mysql.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const mysqlConfig = [ { @@ -14,5 +14,3 @@ export const mysqlModuleNames = getModuleNames(mysqlConfig); export const mysqlChannels = { MYSQL_QUERY: 'orchestrion:mysql:query', } as const; - -export const mysqlSubscribeInjection = toSubscribeInjections(mysqlConfig); diff --git a/packages/server-utils/src/orchestrion/config/mysql2.ts b/packages/server-utils/src/orchestrion/config/mysql2.ts index 8da5685a40a4..0dcb5e7067e4 100644 --- a/packages/server-utils/src/orchestrion/config/mysql2.ts +++ b/packages/server-utils/src/orchestrion/config/mysql2.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // Ports `@opentelemetry/instrumentation-mysql2` (which patches `query`/`execute` on the connection // prototype) to orchestrion channel injection. @@ -49,5 +49,3 @@ export const mysql2Channels = { MYSQL2_QUERY: 'orchestrion:mysql2:query', MYSQL2_EXECUTE: 'orchestrion:mysql2:execute', } as const; - -export const mysql2SubscribeInjection = toSubscribeInjections(mysql2Config); diff --git a/packages/server-utils/src/orchestrion/config/nestjs.ts b/packages/server-utils/src/orchestrion/config/nestjs.ts index d0bd54fdc3d9..fe52895cad55 100644 --- a/packages/server-utils/src/orchestrion/config/nestjs.ts +++ b/packages/server-utils/src/orchestrion/config/nestjs.ts @@ -1,5 +1,4 @@ import type { InstrumentationConfig } from '..'; -import { toSubscribeInjections } from './subscribe-injection'; /** * Wrap an instrumentation that targets nodes via a raw esquery selector @@ -142,5 +141,3 @@ export const nestjsChannels = { NESTJS_ONEVENT: 'orchestrion:@nestjs/event-emitter:onEventDecorator', NESTJS_PROCESSOR: 'orchestrion:@nestjs/bullmq:processorDecorator', } as const; - -export const nestjsSubscribeInjection = toSubscribeInjections(nestjsConfig); diff --git a/packages/server-utils/src/orchestrion/config/openai.ts b/packages/server-utils/src/orchestrion/config/openai.ts index a42f7eda4ede..1d087688c952 100644 --- a/packages/server-utils/src/orchestrion/config/openai.ts +++ b/packages/server-utils/src/orchestrion/config/openai.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const openaiConfig = [ // OpenAI chat completions. `Completions.create` returns a thenable `APIPromise` with no callback arg, @@ -38,5 +38,3 @@ export const openaiChannels = { OPENAI_CHAT: 'orchestrion:openai:chat', OPENAI_EMBEDDINGS: 'orchestrion:openai:embeddings', } as const; - -export const openaiSubscribeInjection = toSubscribeInjections(openaiConfig); diff --git a/packages/server-utils/src/orchestrion/config/pg.ts b/packages/server-utils/src/orchestrion/config/pg.ts index 44ccefdba858..fcfb261dcbab 100644 --- a/packages/server-utils/src/orchestrion/config/pg.ts +++ b/packages/server-utils/src/orchestrion/config/pg.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const pgConfig = [ // `pg` (node-postgres). @@ -49,5 +49,3 @@ export const pgChannels = { PG_CONNECT: 'orchestrion:pg:connect', PGPOOL_CONNECT: 'orchestrion:pg-pool:connect', } as const; - -export const pgSubscribeInjection = toSubscribeInjections(pgConfig); diff --git a/packages/server-utils/src/orchestrion/config/postgres.ts b/packages/server-utils/src/orchestrion/config/postgres.ts index 4be82009a917..8dd899ac2fb7 100644 --- a/packages/server-utils/src/orchestrion/config/postgres.ts +++ b/packages/server-utils/src/orchestrion/config/postgres.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; // postgres.js (`postgres` npm package, v3.x). Named after the npm package; // `postgres` doesn't collide with `pg.ts` (that file instruments `pg`/`pg-pool`). @@ -56,5 +56,3 @@ export const postgresJsChannels = { POSTGRESJS_EXECUTE: 'orchestrion:postgres:execute', POSTGRESJS_CONNECT: 'orchestrion:postgres:connect', } as const; - -export const postgresJsSubscribeInjection = toSubscribeInjections(postgresJsConfig); diff --git a/packages/server-utils/src/orchestrion/config/redis.ts b/packages/server-utils/src/orchestrion/config/redis.ts index e84ca3e13f46..7d5cc56839e4 100644 --- a/packages/server-utils/src/orchestrion/config/redis.ts +++ b/packages/server-utils/src/orchestrion/config/redis.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const redisConfig = [ // redis `>=2.6.0 <4` (standalone `redis`). `internal_send_command` is an @@ -74,5 +74,3 @@ export const redisChannels = { NODE_REDIS_PIPELINE: 'orchestrion:@redis/client:pipeline', NODE_REDIS_BATCH: 'orchestrion:@redis/client:batch', } as const; - -export const redisSubscribeInjection = toSubscribeInjections(redisConfig); diff --git a/packages/server-utils/src/orchestrion/config/remix.ts b/packages/server-utils/src/orchestrion/config/remix.ts index cd2dbcf46b14..893efa781e5a 100644 --- a/packages/server-utils/src/orchestrion/config/remix.ts +++ b/packages/server-utils/src/orchestrion/config/remix.ts @@ -1,5 +1,4 @@ import type { InstrumentationConfig } from '..'; -import { toSubscribeInjections } from './subscribe-injection'; // Four concepts, one channel each: // - `requestHandler` → the async handler returned by `createRequestHandler` (the server span) @@ -58,5 +57,3 @@ export const remixChannels = { REMIX_CALL_ROUTE_LOADER: 'orchestrion:@remix-run/server-runtime:callRouteLoader', REMIX_CALL_ROUTE_ACTION: 'orchestrion:@remix-run/server-runtime:callRouteAction', } as const; - -export const remixSubscribeInjection = toSubscribeInjections(remixConfig); diff --git a/packages/server-utils/src/orchestrion/config/subscribe-injection.ts b/packages/server-utils/src/orchestrion/config/subscribe-injection.ts deleted file mode 100644 index c8001e31d775..000000000000 --- a/packages/server-utils/src/orchestrion/config/subscribe-injection.ts +++ /dev/null @@ -1,63 +0,0 @@ -import type { InstrumentationConfig } from '../apmTypes'; - -/** - * Name shared by the `Program` injection configs (their `transform` field) and - * the custom transform registered on the bundler plugin (its `customTransforms` - * key). Any unique string works — it only has to match on both sides. - * - * Lives in this dependency-free leaf so the per-library config files can build - * their injection configs without importing the transform implementation (which - * pulls in `meriyah` and must never reach the runtime `--import` path). - */ -export const SUBSCRIBE_TRANSFORM_NAME = 'sentrySubscribeOrchestrionChannel'; - -/** - * Turn a library's channel-publishing configs into the `Program`-matching - * injection configs that make each instrumented file self-register its channel - * subscriber (via the {@link SUBSCRIBE_TRANSFORM_NAME} custom transform). - * - * Emits one injection per distinct instrumented file (deduped by module - * matcher), so the subscribe snippet lands in exactly the files that receive - * channels and inherits their precise version ranges. `channelName` carries the - * package name (not a real channel — nothing is wrapped here) so the transform - * can look up which subscriber to import. - * - * Co-located with each library's config (e.g. `mysqlSubscribeInjection`) but - * kept OUT of `SENTRY_INSTRUMENTATIONS`: the runtime `--import` hook consumes - * that list and can't register the custom transform, and an unregistered - * `transform` makes the code-transformer drop the whole file. They are - * aggregated separately into `SUBSCRIBE_INJECTIONS` and only handed to a bundler - * plugin that opts in (and registers the transform). - */ -export function toSubscribeInjections(configs: InstrumentationConfig[]): InstrumentationConfig[] { - const seen = new Set(); - const injections: InstrumentationConfig[] = []; - - for (const { module } of configs) { - const key = `${module.name}\0${module.versionRange}\0${String(module.filePath)}`; - - if (seen.has(key)) { - continue; - } - - seen.add(key); - - injections.push({ - channelName: module.name, - module, - astQuery: 'Program', - transform: SUBSCRIBE_TRANSFORM_NAME, - }); - } - - return injections; -} - -/** - * The distinct instrumented package names (`module.name`) across a library's - * channel configs. Integrations pass this to `invokeOrchestrionInstrumentation` - * so they subscribe only once one of their packages is actually injected. - */ -export function getModuleNames(configs: readonly InstrumentationConfig[]): string[] { - return [...new Set(configs.map(config => config.module.name))]; -} diff --git a/packages/server-utils/src/orchestrion/config/tedious.ts b/packages/server-utils/src/orchestrion/config/tedious.ts index 7c63a3cd8cad..a7c529331cf2 100644 --- a/packages/server-utils/src/orchestrion/config/tedious.ts +++ b/packages/server-utils/src/orchestrion/config/tedious.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; const MODULE_NAME = 'tedious'; @@ -32,5 +32,3 @@ export const tediousChannels = { TEDIOUS_PREPARE: 'orchestrion:tedious:prepare', TEDIOUS_EXECUTE: 'orchestrion:tedious:execute', } as const; - -export const tediousSubscribeInjection = toSubscribeInjections(tediousConfig); diff --git a/packages/server-utils/src/orchestrion/config/vercel-ai.ts b/packages/server-utils/src/orchestrion/config/vercel-ai.ts index be25e300a664..6aa86beba558 100644 --- a/packages/server-utils/src/orchestrion/config/vercel-ai.ts +++ b/packages/server-utils/src/orchestrion/config/vercel-ai.ts @@ -1,5 +1,5 @@ import type { InstrumentationConfig } from '..'; -import { getModuleNames, toSubscribeInjections } from './subscribe-injection'; +import { getModuleNames } from './module-names'; export const vercelAiConfig = [ // Vercel AI v6: mirror the v7 native `ai:telemetry` channel by injecting @@ -71,5 +71,3 @@ function vercelAiEntries( } export const vercelAiModuleNames = getModuleNames(vercelAiConfig); - -export const vercelAiSubscribeInjection = toSubscribeInjections(vercelAiConfig); diff --git a/packages/server-utils/test/orchestrion/config.test.ts b/packages/server-utils/test/orchestrion/config.test.ts index ea8499c8f6f4..ae5899cafdb4 100644 --- a/packages/server-utils/test/orchestrion/config.test.ts +++ b/packages/server-utils/test/orchestrion/config.test.ts @@ -4,9 +4,9 @@ import { INSTRUMENTED_MODULE_NAMES, instrumentedModuleNames, SENTRY_INSTRUMENTATIONS, - SUBSCRIBE_INJECTIONS, withoutInstrumentedExternals, } from '../../src/orchestrion/config'; +import { CHANNEL_INTEGRATION_DEFINITIONS } from '../../src/orchestrion/config/channel-integration-definitions'; describe('orchestrion config — scoped @hapi/hapi module', () => { it('includes the scoped @hapi/hapi name in INSTRUMENTED_MODULE_NAMES', () => { @@ -21,17 +21,17 @@ describe('orchestrion config — scoped @hapi/hapi module', () => { }); }); -describe('orchestrion config — subscribe injection coverage', () => { - // Every instrumented library must contribute a subscribe injection so bundler-only SDKs - // self-register its subscriber. A literal `.length` check is wrong: `toSubscribeInjections` - // dedupes by (module, versionRange, filePath), so one library with many channel configs - // (e.g. redis) collapses to fewer injections. The invariant that must hold is at the - // module-name level — the set of instrumented modules and the set of injected modules match. - it('has a subscribe injection for every instrumented module and vice versa', () => { +describe('orchestrion config — channel-subscriber coverage', () => { + // The subscribe injection rides the real channel configs (the `tracingChannelImport` + // override only runs on instrumented files), so a subscriber definition whose module is + // not instrumented could never self-register — it has to be a config mistake. + it('only defines subscribers for instrumented modules', () => { const instrumentedModules = new Set(SENTRY_INSTRUMENTATIONS.map(i => i.module.name)); - const injectedModules = new Set(SUBSCRIBE_INJECTIONS.map(i => i.module.name)); + const missing = CHANNEL_INTEGRATION_DEFINITIONS.flatMap(d => + d.modules.filter(moduleName => !instrumentedModules.has(moduleName)), + ); - expect([...injectedModules].sort()).toEqual([...instrumentedModules].sort()); + expect(missing).toEqual([]); }); }); diff --git a/packages/server-utils/test/orchestrion/subscribeInjection.test.ts b/packages/server-utils/test/orchestrion/subscribeInjection.test.ts index bbad0d4e0878..0c4002c81234 100644 --- a/packages/server-utils/test/orchestrion/subscribeInjection.test.ts +++ b/packages/server-utils/test/orchestrion/subscribeInjection.test.ts @@ -47,14 +47,14 @@ describe('subscribe-injection transform option', () => { rmSync(root, { recursive: true, force: true }); }); - it('adds Program injection configs and the custom transform only when opted in', () => { + it('registers the tracingChannelImport override only when opted in', () => { const off = orchestrionTransformOptions({}); expect(off.customTransforms).toEqual({}); - expect(off.instrumentations.some(i => i.astQuery === 'Program' && i.transform)).toBe(false); const on = orchestrionTransformOptions({ injectChannelSubscribers: true }); - expect(Object.keys(on.customTransforms || {})).toContain('sentrySubscribeOrchestrionChannel'); - expect(on.instrumentations.some(i => i.astQuery === 'Program' && i.transform)).toBe(true); + expect(Object.keys(on.customTransforms || {})).toContain('tracingChannelImport'); + // The override rides the real channel configs — opting in adds no extra ones. + expect(on.instrumentations).toEqual(off.instrumentations); }); it('injects a CJS marker-push importing only that package factory, after "use strict"', () => { diff --git a/yarn.lock b/yarn.lock index c5c4cf35fb14..54f87bb8d4af 100644 --- a/yarn.lock +++ b/yarn.lock @@ -415,9 +415,9 @@ module-details-from-path "^1.0.4" "@apm-js-collab/code-transformer@^0.18.0": - version "0.18.0" - resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.18.0.tgz#722972c05f04bc37f4bbd5067f42ffd7a990eee9" - integrity sha512-aN3Oq8r1J3gPJtCwErP664gM0+HhM1I1lujPr9TMTCcEl/joQQbpGpeMdts9B1+W2wHMsvioDMv5F4PvMWE6gw== + version "0.18.1" + resolved "https://registry.yarnpkg.com/@apm-js-collab/code-transformer/-/code-transformer-0.18.1.tgz#66ce01cfe9607779b4abebb4f54c49a46e8b48ca" + integrity sha512-u1Hb6bHjWtkSpiprwVP6YaHC1DTN4RAU3zYkUDUe7WMnJwdyU1pwTL9dFKiSJB9IiLue/EQovmyx6xhU7FFtAQ== dependencies: "@types/estree" "^1.0.8" astring "^1.9.0"