diff --git a/dev-packages/node-integration-tests/suites/tracing/orchestrion-lazy-registration/scenario-bundler.mjs b/dev-packages/node-integration-tests/suites/tracing/orchestrion-lazy-registration/scenario-bundler.mjs index 5eca4672935a..cf95fb81f340 100644 --- a/dev-packages/node-integration-tests/suites/tracing/orchestrion-lazy-registration/scenario-bundler.mjs +++ b/dev-packages/node-integration-tests/suites/tracing/orchestrion-lazy-registration/scenario-bundler.mjs @@ -1,6 +1,6 @@ import { strict as assert } from 'node:assert'; import { tracingChannel } from 'node:diagnostics_channel'; -import { orchestrionModuleInjected } from '@sentry/server-utils/orchestrion'; +import { orchestrionModuleInjected } from '@sentry/server-utils'; // Reproduces the force-bundled path (vite SSR, nextjs's bundle-safe packages): // the module is transformed at BUILD time and inlined, so it is never loaded diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index aa392eb3ec4d..554c80500f1f 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -172,7 +172,7 @@ export { rewriteFramesIntegration, } from '@sentry/core'; -export { awsIntegration } from '@sentry/server-utils/orchestrion'; +export { awsIntegration } from '@sentry/server-utils'; export { awsLambdaIntegration } from './integration/awslambda'; export { getDefaultIntegrations, init } from './init'; diff --git a/packages/aws-serverless/src/init.ts b/packages/aws-serverless/src/init.ts index b02f4ff69dbb..8c7c238265fa 100644 --- a/packages/aws-serverless/src/init.ts +++ b/packages/aws-serverless/src/init.ts @@ -2,7 +2,7 @@ import type { Integration, Options } from '@sentry/core'; import { applySdkMetadata, debug, envToBool, getSDKSource } from '@sentry/core'; import type { NodeClient, NodeOptions } from '@sentry/node'; import { getDefaultIntegrationsWithoutPerformance, initWithoutDefaultIntegrations } from '@sentry/node'; -import { awsIntegration } from '@sentry/server-utils/orchestrion'; +import { awsIntegration } from '@sentry/server-utils'; import { DEBUG_BUILD } from './debug-build'; import { awsLambdaIntegration } from './integration/awslambda'; diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 4a2fb8a69329..059362ee3297 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -133,8 +133,8 @@ export { instrumentLangChainEmbeddings, instrumentStateGraph, instrumentCreateReactAgent, + vercelAIIntegration, } from '@sentry/server-utils'; -export { vercelAIIntegration } from '@sentry/server-utils/orchestrion'; export { instrumentWorkflowWithSentry } from './workflows'; diff --git a/packages/cloudflare/src/sdk.ts b/packages/cloudflare/src/sdk.ts index ae80731cf3b4..fc62ff35e0c1 100644 --- a/packages/cloudflare/src/sdk.ts +++ b/packages/cloudflare/src/sdk.ts @@ -1,7 +1,7 @@ import type { Integration } from '@sentry/core'; import { getBaseDefaultIntegrations, initWithDefaultIntegrations } from './baseSdk'; import type { CloudflareClient, CloudflareOptions } from './client'; -import { vercelAIIntegration } from '@sentry/server-utils/orchestrion'; +import { vercelAIIntegration } from '@sentry/server-utils'; /** * Get the default integrations for the Cloudflare SDK. diff --git a/packages/cloudflare/test/sdk.test.ts b/packages/cloudflare/test/sdk.test.ts index edac98354fc0..e706e5465fb3 100644 --- a/packages/cloudflare/test/sdk.test.ts +++ b/packages/cloudflare/test/sdk.test.ts @@ -112,8 +112,7 @@ describe('getDefaultIntegrations', () => { // Mirror what the snippet the vite plugin injects into each instrumented // module does at runtime: import its factory and `.set` it on the marker map, // keyed by module name (so a package split across files registers once). - const { mysqlIntegration, postgresIntegration, lruMemoizerIntegration } = - await import('@sentry/server-utils/orchestrion'); + const { mysqlIntegration, postgresIntegration, lruMemoizerIntegration } = await import('@sentry/server-utils'); globalThis.__SENTRY_ORCHESTRION__ = { bundler: ['mysql', 'pg', 'lru-memoizer'], integrations: new Map([ @@ -131,7 +130,7 @@ describe('getDefaultIntegrations', () => { }); test('installs an integration registered after init via the module-injected event', async () => { - const { mysqlIntegration } = await import('@sentry/server-utils/orchestrion'); + const { mysqlIntegration } = await import('@sentry/server-utils'); const client = init({}); expect(client?.getIntegrationByName('Mysql')).toBeUndefined(); diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index 476e6649f29f..b5dd460093c8 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -142,7 +142,7 @@ export { postgresIntegration, postgresJsIntegration, tediousIntegration, -} from '@sentry/server-utils/orchestrion'; +} from '@sentry/server-utils'; export { otlpIntegration, getOtlpTracesEndpoint } from '@sentry/server-utils/no-diagnostic-channels'; // Deprecated aliases kept for back-compat. Each forwards to the shared // integration above, so its name is the shared name (e.g. `Mysql`), not the old diff --git a/packages/deno/src/integrations/amqplib.ts b/packages/deno/src/integrations/amqplib.ts index 835f91832c95..17492a64ee58 100644 --- a/packages/deno/src/integrations/amqplib.ts +++ b/packages/deno/src/integrations/amqplib.ts @@ -1,4 +1,4 @@ -import { amqplibIntegration } from '@sentry/server-utils/orchestrion'; +import { amqplibIntegration } from '@sentry/server-utils'; /** * Create spans for `amqplib` publish/consume operations under Deno. Included in diff --git a/packages/deno/src/integrations/dataloader.ts b/packages/deno/src/integrations/dataloader.ts index c87abc10870a..bd8093e30cb6 100644 --- a/packages/deno/src/integrations/dataloader.ts +++ b/packages/deno/src/integrations/dataloader.ts @@ -1,4 +1,4 @@ -import { dataloaderIntegration } from '@sentry/server-utils/orchestrion'; +import { dataloaderIntegration } from '@sentry/server-utils'; /** * Create spans for `dataloader` load/batch operations under Deno. Not a default; diff --git a/packages/deno/src/integrations/knex.ts b/packages/deno/src/integrations/knex.ts index 234efb95f196..9827bebd14e1 100644 --- a/packages/deno/src/integrations/knex.ts +++ b/packages/deno/src/integrations/knex.ts @@ -1,4 +1,4 @@ -import { knexIntegration } from '@sentry/server-utils/orchestrion'; +import { knexIntegration } from '@sentry/server-utils'; /** * Create spans for `knex` queries under Deno. Not a default; add it to diff --git a/packages/deno/src/integrations/koa.ts b/packages/deno/src/integrations/koa.ts index 407b42b1d123..f7335c0724d7 100644 --- a/packages/deno/src/integrations/koa.ts +++ b/packages/deno/src/integrations/koa.ts @@ -1,4 +1,4 @@ -import { koaIntegration } from '@sentry/server-utils/orchestrion'; +import { koaIntegration } from '@sentry/server-utils'; /** * Create spans for `koa` middleware/router layers under Deno. Included in the diff --git a/packages/deno/src/integrations/mongoose.ts b/packages/deno/src/integrations/mongoose.ts index be44a66e1698..45758ed1f882 100644 --- a/packages/deno/src/integrations/mongoose.ts +++ b/packages/deno/src/integrations/mongoose.ts @@ -1,4 +1,4 @@ -import { mongooseIntegration } from '@sentry/server-utils/orchestrion'; +import { mongooseIntegration } from '@sentry/server-utils'; /** * Create spans for `mongoose` queries under Deno. Included in the default diff --git a/packages/deno/src/integrations/mysql.ts b/packages/deno/src/integrations/mysql.ts index 3fc1ad3f7c9c..8d9073db3906 100644 --- a/packages/deno/src/integrations/mysql.ts +++ b/packages/deno/src/integrations/mysql.ts @@ -1,4 +1,4 @@ -import { mysqlIntegration } from '@sentry/server-utils/orchestrion'; +import { mysqlIntegration } from '@sentry/server-utils'; /** * Create spans for `mysql` queries under Deno. Included in the default diff --git a/packages/deno/src/integrations/postgres.ts b/packages/deno/src/integrations/postgres.ts index cbbba652b5e8..9fd80ee45384 100644 --- a/packages/deno/src/integrations/postgres.ts +++ b/packages/deno/src/integrations/postgres.ts @@ -1,4 +1,4 @@ -import { postgresIntegration } from '@sentry/server-utils/orchestrion'; +import { postgresIntegration } from '@sentry/server-utils'; /** * Create spans for `pg` (node-postgres) queries under Deno. Included in the diff --git a/packages/deno/src/integrations/redis.ts b/packages/deno/src/integrations/redis.ts index 7dc110b9ca0c..34cac39c22a3 100644 --- a/packages/deno/src/integrations/redis.ts +++ b/packages/deno/src/integrations/redis.ts @@ -1,4 +1,4 @@ -import { redisIntegration } from '@sentry/server-utils/orchestrion'; +import { redisIntegration } from '@sentry/server-utils'; /** * @deprecated Use `redisIntegration` instead. diff --git a/packages/deno/src/integrations/tracing/vercelai.ts b/packages/deno/src/integrations/tracing/vercelai.ts index 965c61f09732..8b22585542f1 100644 --- a/packages/deno/src/integrations/tracing/vercelai.ts +++ b/packages/deno/src/integrations/tracing/vercelai.ts @@ -1 +1 @@ -export { vercelAIIntegration } from '@sentry/server-utils/orchestrion'; +export { vercelAIIntegration } from '@sentry/server-utils'; diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index 629d96f914e0..b4867e6f61b4 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -36,7 +36,7 @@ import { tediousIntegration, vercelAIIntegration, redisIntegration, -} from '@sentry/server-utils/orchestrion'; +} from '@sentry/server-utils'; import { DenoClient } from './client'; import { breadcrumbsIntegration } from './integrations/breadcrumbs'; import { denoContextIntegration } from './integrations/context'; diff --git a/packages/nestjs/src/integrations/orchestrion-subscriber.ts b/packages/nestjs/src/integrations/orchestrion-subscriber.ts index 2d72eb28e5e8..313300853627 100644 --- a/packages/nestjs/src/integrations/orchestrion-subscriber.ts +++ b/packages/nestjs/src/integrations/orchestrion-subscriber.ts @@ -1,7 +1,7 @@ import * as diagnosticsChannel from 'node:diagnostics_channel'; import { debug, startInactiveSpan, waitForTracingChannelBinding } from '@sentry/core'; import { bindTracingChannelToSpan } from '@sentry/server-utils'; -import { nestjsChannels as CHANNELS } from '@sentry/server-utils/orchestrion'; +import { nestjsChannels as CHANNELS } from '@sentry/server-utils/orchestrion/config'; import { DEBUG_BUILD } from '../debug-build'; import type { AnyFn } from './helpers'; import { isWrapped, markWrapped } from './helpers'; @@ -114,8 +114,7 @@ function subscribeFactoryDecorator(channelName: string, wrap: (decorator: AnyFn, * Opens the same spans as the OTel `Nest` instrumentation, only with * different origin. * - * Called from `nestIntegration`'s `setupOnce` when orchestrion is active - * (`isOrchestrionInjected()`); requires the runtime hook or bundler plugin. + * Called from `nestIntegration`'s `setupOnce` when orchestrion is active. */ export function subscribeToNestChannels(): void { if (!diagnosticsChannel.tracingChannel) { diff --git a/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts b/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts index 8844661a7581..d683cef828a8 100644 --- a/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts +++ b/packages/nestjs/test/integrations/orchestrion-subscriber.test.ts @@ -15,7 +15,7 @@ import { spanToJSON, } from '@sentry/core'; import { afterEach, describe, expect, it, vi } from 'vitest'; -import { nestjsChannels as CHANNELS } from '@sentry/server-utils/orchestrion'; +import { nestjsChannels as CHANNELS } from '@sentry/server-utils/orchestrion/config'; import { subscribeToNestChannels } from '../../src/integrations/orchestrion-subscriber'; // Mirrors harness in `tracing-channel.test.ts`: `bindTracingChannelToSpan` diff --git a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts index dbd10e1f1d9f..8c2c392f7a6a 100644 --- a/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts +++ b/packages/nextjs/src/config/turbopack/constructTurbopackConfig.ts @@ -154,13 +154,14 @@ function maybeAddOrchestrionRule( return rules; } - // The loader's transform splices an import of the `@sentry/server-utils/orchestrion` helper into - // each instrumented module. Turbopack rejects absolute-path imports ("server relative imports are - // not implemented yet"), and under isolated installs (pnpm) the bare specifier emitted inside a - // bundled package doesn't resolve from that package's location — so pass the helper's absolute - // on-disk path and let the loader derive a per-file RELATIVE specifier, which Turbopack resolves - // from the importing file and bundles at build time. - const importHelperPath = resolveOrchestrionRuntimeRequest('@sentry/server-utils/orchestrion'); + // The loader's transform splices an import of `@sentry/server-utils` (the module-injected helper + // plus the module's subscriber factory) into each instrumented module. Turbopack rejects + // absolute-path imports ("server relative imports are not implemented yet"), and under isolated + // installs (pnpm) the bare specifier emitted inside a bundled package doesn't resolve from that + // package's location — so pass the entry's absolute on-disk path and let the loader derive a + // per-file RELATIVE specifier, which Turbopack resolves from the importing file and bundles at + // build time. + const importHelperPath = resolveOrchestrionRuntimeRequest('@sentry/server-utils'); return safelyAddTurbopackRule(rules, { matcher: '*.{js,mjs,cjs}', diff --git a/packages/nextjs/test/config/diagnosticsChannelInjection.test.ts b/packages/nextjs/test/config/diagnosticsChannelInjection.test.ts index d62db8471974..4790ce65d540 100644 --- a/packages/nextjs/test/config/diagnosticsChannelInjection.test.ts +++ b/packages/nextjs/test/config/diagnosticsChannelInjection.test.ts @@ -62,7 +62,7 @@ describe('externalizeOrchestrionRuntimePackages', () => { // An absolute path here breaks every deploy that relocates the output, so it has to stay bare. it.each([ ['@sentry/server-utils', '@sentry/nextjs/orchestrion-runtime/index'], - ['@sentry/server-utils/orchestrion', '@sentry/nextjs/orchestrion-runtime/orchestrion'], + ['@sentry/server-utils/orchestrion/config', '@sentry/nextjs/orchestrion-runtime/orchestrion/config'], ['@sentry/server-utils/orchestrion/register', '@sentry/nextjs/orchestrion-runtime/orchestrion/register'], ['@sentry/server-utils/orchestrion/webpack', '@sentry/nextjs/orchestrion-runtime/orchestrion/webpack'], ])('externalizes %s as the relocatable bare specifier %s', async (request, expected) => { diff --git a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts index 296fff43934e..c0479119ef2d 100644 --- a/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts +++ b/packages/nextjs/test/config/turbopack/constructTurbopackConfig.test.ts @@ -1481,7 +1481,7 @@ describe('orchestrion build-time instrumentation', () => { expect(JSON.parse(JSON.stringify(firestore!.module.filePath))).not.toEqual({}); }); - it('passes the helper module as an absolute importHelperPath', () => { + it('passes the snippet module as an absolute importHelperPath', () => { const result = constructTurbopackConfig({ userNextConfig: {}, userSentryOptions: {}, @@ -1496,9 +1496,12 @@ describe('orchestrion build-time instrumentation', () => { // The loader derives a per-file RELATIVE specifier from this path — // Turbopack rejects absolute-path imports, and a bare specifier doesn't // resolve from inside a transformed package under isolated installs (pnpm). + // The snippet imports the helper and the subscriber factory from + // `@sentry/server-utils` (the main entry), not the orchestrion subpath. expect(importHelperPath).toBeDefined(); expect(path.isAbsolute(importHelperPath!)).toBe(true); - expect(importHelperPath).toContain('orchestrion'); + expect(importHelperPath).toContain('server-utils'); + expect(importHelperPath).not.toContain('orchestrion'); }); it('restricts the orchestrion rule to the node environment', () => { diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 3483dbff8163..1dc1160e16de 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -29,7 +29,7 @@ export { redisIntegration, tediousIntegration, vercelAIIntegration, -} from '@sentry/server-utils/orchestrion'; +} from '@sentry/server-utils'; export { otlpIntegration, getOtlpTracesEndpoint, diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index 2d7274326a40..e01d0d36bd38 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -1,6 +1,6 @@ import type { Integration } from '@sentry/core'; -import { prismaIntegration } from '@sentry/server-utils'; import { + prismaIntegration, amqplibIntegration, anthropicAIIntegration, expressIntegration, @@ -24,7 +24,7 @@ import { redisIntegration, tediousIntegration, vercelAIIntegration, -} from '@sentry/server-utils/orchestrion'; +} from '@sentry/server-utils'; import { fastifyIntegration } from './fastify'; export function getAutoPerformanceIntegrations(): Integration[] { diff --git a/packages/node/src/sdk/index.ts b/packages/node/src/sdk/index.ts index 9d0da79809cc..c7f55b9b17eb 100644 --- a/packages/node/src/sdk/index.ts +++ b/packages/node/src/sdk/index.ts @@ -16,9 +16,8 @@ import { stackParserFromStackParserOptions, } from '@sentry/core'; import { setOpenTelemetryContextAsyncContextStrategy } from '@sentry/opentelemetry'; -import { setAsyncLocalStorageAsyncContextStrategy } from '@sentry/server-utils'; +import { setAsyncLocalStorageAsyncContextStrategy, detectOrchestrionSetup } from '@sentry/server-utils'; import { isMainThread, parentPort } from 'node:worker_threads'; -import { detectOrchestrionSetup } from '@sentry/server-utils/orchestrion'; import { registerDiagnosticsChannelInjection } from '@sentry/server-utils/orchestrion/register'; import { DEBUG_BUILD } from '../debug-build'; import { childProcessIntegration } from '../integrations/childProcess'; diff --git a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts index e06405efaae9..cbeee7171f7f 100644 --- a/packages/node/test/sdk/diagnosticsChannelInjection.test.ts +++ b/packages/node/test/sdk/diagnosticsChannelInjection.test.ts @@ -9,7 +9,7 @@ const { registerDiagnosticsChannelInjection, detectOrchestrionSetup } = vi.hoist vi.mock('@sentry/server-utils/orchestrion/register', () => ({ registerDiagnosticsChannelInjection, })); -vi.mock('@sentry/server-utils/orchestrion', async importOriginal => { +vi.mock('@sentry/server-utils', async importOriginal => { const actual = (await importOriginal()) as Record; return { ...actual, detectOrchestrionSetup }; }); diff --git a/packages/remix/src/server/integrations/tracing-channel.ts b/packages/remix/src/server/integrations/tracing-channel.ts index d2fbc5689a73..b37c9eec28c0 100644 --- a/packages/remix/src/server/integrations/tracing-channel.ts +++ b/packages/remix/src/server/integrations/tracing-channel.ts @@ -27,7 +27,7 @@ import { HTTP_RESPONSE_STATUS_CODE, } from '@sentry/conventions/attributes'; import { WEB_SERVER_FUNCTION_SPAN_OP } from '@sentry/conventions/op'; -import { remixChannels } from '@sentry/server-utils/orchestrion'; +import { remixChannels } from '@sentry/server-utils/orchestrion/config'; import type { FormDataCapture } from '../../utils/formData'; import { applyFormDataAttributes } from '../../utils/formData'; diff --git a/packages/remix/test/server/tracing-channel-no-form-data.test.ts b/packages/remix/test/server/tracing-channel-no-form-data.test.ts index 13441e44d25a..6c42e24610e8 100644 --- a/packages/remix/test/server/tracing-channel-no-form-data.test.ts +++ b/packages/remix/test/server/tracing-channel-no-form-data.test.ts @@ -8,7 +8,7 @@ import { setupRemixInstrumentation, teardownTestAsyncContextStrategy, } from './tracing-channel-test-utils'; -import { remixChannels } from '@sentry/server-utils/orchestrion'; +import { remixChannels } from '@sentry/server-utils/orchestrion/config'; // Runs in its own file so the channel subscriptions register with NO form-data capture configured - // the default for most apps. `captureActionFormDataKeys` gates only the optional attribute diff --git a/packages/remix/test/server/tracing-channel.test.ts b/packages/remix/test/server/tracing-channel.test.ts index 591aa55da8cf..5f1983bc075d 100644 --- a/packages/remix/test/server/tracing-channel.test.ts +++ b/packages/remix/test/server/tracing-channel.test.ts @@ -8,7 +8,7 @@ import { setupRemixInstrumentation, teardownTestAsyncContextStrategy, } from './tracing-channel-test-utils'; -import { remixChannels } from '@sentry/server-utils/orchestrion'; +import { remixChannels } from '@sentry/server-utils/orchestrion/config'; describe('remixIntegration (Orchestrion-based)', () => { let startInactiveSpanSpy: MockInstance; diff --git a/packages/server-utils/package.json b/packages/server-utils/package.json index 8a4d2b05fd27..991830493feb 100644 --- a/packages/server-utils/package.json +++ b/packages/server-utils/package.json @@ -27,11 +27,6 @@ "import": "./build/esm/index.no-diagnostic-channels.js", "require": "./build/cjs/index.no-diagnostic-channels.js" }, - "./orchestrion": { - "types": "./build/types/orchestrion/index.d.ts", - "import": "./build/esm/orchestrion/index.js", - "require": "./build/cjs/orchestrion/index.js" - }, "./orchestrion/config": { "types": "./build/types/orchestrion/config/index.d.ts", "import": "./build/esm/orchestrion/config/index.js", diff --git a/packages/server-utils/rollup.npm.config.mjs b/packages/server-utils/rollup.npm.config.mjs index e79218e1cd83..6b7c30b5a292 100644 --- a/packages/server-utils/rollup.npm.config.mjs +++ b/packages/server-utils/rollup.npm.config.mjs @@ -100,12 +100,10 @@ export default [ // plugins are loaded via dedicated subpath exports (`.../orchestrion/config`, // `.../orchestrion/vite`, etc.) — none are reachable from `src/index.ts`, so // we list them as separate entrypoints to guarantee they end up in build/esm - // and build/cjs. `src/orchestrion/index.ts` backs the `./orchestrion` - // subpath export. + // and build/cjs. entrypoints: [ 'src/index.ts', 'src/index.no-diagnostic-channels.ts', - 'src/orchestrion/index.ts', 'src/orchestrion/config/index.ts', // `src/orchestrion/runtime/register.ts` backs the `./orchestrion/register` // subpath export; the Node SDK `require`s it synchronously from diff --git a/packages/server-utils/src/index.ts b/packages/server-utils/src/index.ts index bef2f465f32a..0ad0598dedfd 100644 --- a/packages/server-utils/src/index.ts +++ b/packages/server-utils/src/index.ts @@ -1,11 +1,15 @@ export * from './exports'; // Exports using diagnostics channels -export { prismaIntegration } from './prisma'; +export { detectOrchestrionSetup } from './orchestrion/detect'; export { bindTracingChannelToSpan } from './tracing-channel'; export type { TracingChannelPayloadWithSpan } from './tracing-channel'; -export type { InstrumentationConfig } from './orchestrion'; -export { vercelAIIntegration } from './vercel-ai'; +export type { InstrumentationConfig } from './orchestrion/apmTypes'; +// Runtime target of the bundler-injected module snippet. The snippet imports it +// from this entry alongside the module's subscriber factory (see +// `orchestrion/bundler/moduleInjectedTransform.ts`); it is a plain runtime +// helper with no orchestrion build-time dependency. +export { orchestrionModuleInjected } from './utils/moduleInjected'; export { fastifyIntegration, // oxlint-disable-next-line typescript/no-deprecated @@ -13,3 +17,32 @@ export { // oxlint-disable-next-line typescript/no-deprecated instrumentFastify, } from './integrations/fastify'; + +// Integrations +export { prismaIntegration } from './integrations/prisma'; +export { amqplibIntegration } from './integrations/amqplib'; +export { anthropicAIIntegration } from './integrations/anthropic'; +export { awsIntegration } from './integrations/aws-sdk'; +export { dataloaderIntegration } from './integrations/dataloader'; +export { genericPoolIntegration } from './integrations/generic-pool'; +export { googleGenAIIntegration } from './integrations/google-genai'; +export { graphqlIntegration } from './integrations/graphql'; +export { hapiIntegration } from './integrations/hapi'; +export { koaIntegration } from './integrations/koa'; +export { redisIntegration } from './integrations/redis'; +export { kafkaIntegration } from './integrations/kafkajs'; +export { knexIntegration } from './integrations/knex'; +export { langChainIntegration } from './integrations/langchain'; +export { langGraphIntegration } from './integrations/langgraph'; +export { lruMemoizerIntegration } from './integrations/lru-memoizer'; +export { mongoIntegration } from './integrations/mongodb'; +export { mongooseIntegration } from './integrations/mongoose'; +export { mysqlIntegration } from './integrations/mysql'; +export { mysql2Integration } from './integrations/mysql2'; +export { openAIIntegration } from './integrations/openai'; +export { postgresIntegration } from './integrations/postgres'; +export { postgresJsIntegration } from './integrations/postgres-js'; +export { tediousIntegration } from './integrations/tedious'; +export { vercelAIIntegration } from './integrations/vercel-ai'; +export { expressIntegration } from './integrations/express'; +export { firebaseIntegration } from './integrations/firebase'; diff --git a/packages/server-utils/src/prisma/global.ts b/packages/server-utils/src/integrations/prisma/global.ts similarity index 100% rename from packages/server-utils/src/prisma/global.ts rename to packages/server-utils/src/integrations/prisma/global.ts diff --git a/packages/server-utils/src/prisma/index.ts b/packages/server-utils/src/integrations/prisma/index.ts similarity index 100% rename from packages/server-utils/src/prisma/index.ts rename to packages/server-utils/src/integrations/prisma/index.ts diff --git a/packages/server-utils/src/prisma/tracing-helper.ts b/packages/server-utils/src/integrations/prisma/tracing-helper.ts similarity index 99% rename from packages/server-utils/src/prisma/tracing-helper.ts rename to packages/server-utils/src/integrations/prisma/tracing-helper.ts index c14e90802219..20f1e3552d18 100644 --- a/packages/server-utils/src/prisma/tracing-helper.ts +++ b/packages/server-utils/src/integrations/prisma/tracing-helper.ts @@ -22,7 +22,7 @@ import { startInactiveSpan, startSpanManual, } from '@sentry/core'; -import { DEBUG_BUILD } from '../debug-build'; +import { DEBUG_BUILD } from '../../debug-build'; import type { EngineSpan, ExtendedSpanOptions, SpanCallback, TracingHelper } from './types'; import { DB_STATEMENT, DB_SYSTEM, DB_SYSTEM_NAME, SENTRY_KIND, SENTRY_OP } from '@sentry/conventions/attributes'; diff --git a/packages/server-utils/src/prisma/types.ts b/packages/server-utils/src/integrations/prisma/types.ts similarity index 100% rename from packages/server-utils/src/prisma/types.ts rename to packages/server-utils/src/integrations/prisma/types.ts diff --git a/packages/server-utils/src/integrations/vercel-ai.ts b/packages/server-utils/src/integrations/vercel-ai.ts deleted file mode 100644 index 08c754089c39..000000000000 --- a/packages/server-utils/src/integrations/vercel-ai.ts +++ /dev/null @@ -1,41 +0,0 @@ -import type { Client, IntegrationFn } from '@sentry/core'; -import { defineIntegration, extendIntegration } from '@sentry/core'; -import { vercelAIIntegration as baseVercelAIIntegration } from '../vercel-ai'; -import * as dc from 'node:diagnostics_channel'; -import { vercelAiModuleNames } from '../orchestrion/config/vercel-ai'; -import { invokeOrchestrionInstrumentation } from '../orchestrion/instrumentation'; -import { subscribeVercelAiOrchestrionChannels } from '../vercel-ai/vercel-ai-orchestrion-subscriber'; - -type VercelAiOptions = Parameters[0]; - -// In channel-based (orchestrion) mode we emit our own `gen_ai.*` spans from the -// diagnostics channels. The `ai` SDK would otherwise emit its own native -// OpenTelemetry spans whenever the user enables `experimental_telemetry`, which -// would be duplicates. Rather than dropping those after the fact, the v6 -// subscriber suppresses them at the source: it flips the wrapped call's -// `experimental_telemetry.isEnabled` to `false`, so `ai` falls back to its -// internal no-op tracer and never creates the native spans in the first place. -// See `subscribeVercelAiOrchestrionChannels`. -const _vercelAIIntegration = ((options: VercelAiOptions = {}) => { - const parentIntegration = baseVercelAIIntegration(options); - - // The native `ai:telemetry` half is the base integration's own `setupOnce`; the - // orchestrion half registers lazily via `setup`, only once `ai` is injected. - return extendIntegration(parentIntegration, { - options, - setup(client: Client) { - invokeOrchestrionInstrumentation(client, vercelAiModuleNames, instrumentVercelAiOrchestrion, [options]); - }, - }); -}) satisfies IntegrationFn; - -function instrumentVercelAiOrchestrion(options: VercelAiOptions): void { - subscribeVercelAiOrchestrionChannels(dc.tracingChannel, options); -} - -/** - * Auto-instrument the `ai` SDK. Supported are: - * - v7 via native `ai:telemetry` tracing channel - * - v4, v5 & v6 via orchestrion `orchestrion:ai:*` channels - */ -export const vercelAIIntegration = defineIntegration(_vercelAIIntegration); diff --git a/packages/server-utils/src/vercel-ai/index.ts b/packages/server-utils/src/integrations/vercel-ai/index.ts similarity index 56% rename from packages/server-utils/src/vercel-ai/index.ts rename to packages/server-utils/src/integrations/vercel-ai/index.ts index a8febea59aef..87457e9cb857 100644 --- a/packages/server-utils/src/vercel-ai/index.ts +++ b/packages/server-utils/src/integrations/vercel-ai/index.ts @@ -1,7 +1,10 @@ import { defineIntegration, waitForTracingChannelBinding, type IntegrationFn } from '@sentry/core'; -import type { GenAiOptions } from '../ai/core/utils'; +import type { GenAiOptions } from '../../ai/core/utils'; import { subscribeVercelAiTracingChannel } from './vercel-ai-dc-subscriber'; import * as dc from 'node:diagnostics_channel'; +import { invokeOrchestrionInstrumentation } from '../../orchestrion/instrumentation'; +import { vercelAiModuleNames } from '../../orchestrion/config/vercel-ai'; +import { subscribeVercelAiOrchestrionChannels } from './vercel-ai-orchestrion-subscriber'; /** Options for the Vercel AI integration. */ export type VercelAiOptions = GenAiOptions; @@ -21,10 +24,19 @@ const _vercelAIIntegration = ((options: VercelAiOptions = {}) => { subscribeVercelAiTracingChannel(dc.tracingChannel, options); }); }, + setup(client) { + invokeOrchestrionInstrumentation(client, vercelAiModuleNames, instrumentVercelAiOrchestrion, [options]); + }, }; }) satisfies IntegrationFn; /** - * Auto-instrument the `ai` SDK's native telemetry tracing channel (ai >= 7). + * Auto-instrument the `ai` SDK. Supported are: + * - v7 via native `ai:telemetry` tracing channel + * - v4, v5 & v6 via orchestrion `orchestrion:ai:*` channels */ export const vercelAIIntegration = defineIntegration(_vercelAIIntegration); + +function instrumentVercelAiOrchestrion(options: VercelAiOptions): void { + subscribeVercelAiOrchestrionChannels(dc.tracingChannel, options); +} diff --git a/packages/server-utils/src/vercel-ai/util.ts b/packages/server-utils/src/integrations/vercel-ai/util.ts similarity index 100% rename from packages/server-utils/src/vercel-ai/util.ts rename to packages/server-utils/src/integrations/vercel-ai/util.ts diff --git a/packages/server-utils/src/vercel-ai/vercel-ai-dc-subscriber.ts b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts similarity index 99% rename from packages/server-utils/src/vercel-ai/vercel-ai-dc-subscriber.ts rename to packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts index fc9e3f85b10d..449fa12005e8 100644 --- a/packages/server-utils/src/vercel-ai/vercel-ai-dc-subscriber.ts +++ b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-dc-subscriber.ts @@ -36,10 +36,10 @@ import { withScope, } from '@sentry/core'; import type { TracingChannel } from 'node:diagnostics_channel'; -import type { GenAiOptions } from '../ai/core/utils'; -import { getProviderMetadataAttributes } from '../ai/vercel-ai'; -import { WORKERS_AI_INTEGRATION_NAME } from '../ai/workers-ai/constants'; -import { bindTracingChannelToSpan } from '../tracing-channel'; +import type { GenAiOptions } from '../../ai/core/utils'; +import { getProviderMetadataAttributes } from '../../ai/vercel-ai'; +import { WORKERS_AI_INTEGRATION_NAME } from '../../ai/workers-ai/constants'; +import { bindTracingChannelToSpan } from '../../tracing-channel'; import { asNumber, asString, isReadableStream, type StreamedModelCallResult, sum, tapModelCallStream } from './util'; /** diff --git a/packages/server-utils/src/vercel-ai/vercel-ai-orchestrion-subscriber.ts b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-orchestrion-subscriber.ts similarity index 99% rename from packages/server-utils/src/vercel-ai/vercel-ai-orchestrion-subscriber.ts rename to packages/server-utils/src/integrations/vercel-ai/vercel-ai-orchestrion-subscriber.ts index 72fc3a04b4bc..a03b4e5269f0 100644 --- a/packages/server-utils/src/vercel-ai/vercel-ai-orchestrion-subscriber.ts +++ b/packages/server-utils/src/integrations/vercel-ai/vercel-ai-orchestrion-subscriber.ts @@ -8,9 +8,9 @@ import { SPAN_STATUS_ERROR, withActiveSpan, } from '@sentry/core'; -import { DEBUG_BUILD } from '../debug-build'; -import { CHANNELS } from '../orchestrion/channels'; -import { bindTracingChannelToSpan, type TracingChannelPayloadWithSpan } from '../tracing-channel'; +import { DEBUG_BUILD } from '../../debug-build'; +import { CHANNELS } from '../../orchestrion/channels'; +import { bindTracingChannelToSpan, type TracingChannelPayloadWithSpan } from '../../tracing-channel'; import { captureToolError, clearOperationCallId, diff --git a/packages/server-utils/src/orchestrion/bundler/esbuild.ts b/packages/server-utils/src/orchestrion/bundler/esbuild.ts index 6a329554c8c8..1a7d71516770 100644 --- a/packages/server-utils/src/orchestrion/bundler/esbuild.ts +++ b/packages/server-utils/src/orchestrion/bundler/esbuild.ts @@ -4,7 +4,7 @@ import { escapeStringForRegex } from '@sentry/core'; import { instrumentedModuleNames } from '../config'; import type { PluginOptions } from './options'; import { externalEntryMatchesModule, externalizedModulesWarning, orchestrionTransformOptions } from './options'; -import { resolveOrchestrionRuntimeRequest } from './resolve'; +import { resolveOrchestrionRuntimeRequest, SNIPPET_IMPORT_SPECIFIER_FILTER } from './resolve'; // esbuild `external` entries may contain `*` wildcards. function matchesEsbuildExternal(entry: string, moduleName: string): boolean { @@ -51,13 +51,13 @@ export function sentryOrchestrionPlugin(options: PluginOptions = {}): Plugin { build.onStart(() => ({ warnings: [{ text: externalizedModulesWarning(externalizedModules) }] })); } - // The module-injected snippet imports `@sentry/server-utils/orchestrion` - // from INSIDE transformed `node_modules` files. Under isolated installs - // (pnpm) that bare specifier doesn't resolve from an instrumented - // package's location, so try esbuild's own resolution first (the - // `pluginData` marker stops the recursion back into this callback) and - // fall back to this package's own resolution. - build.onResolve({ filter: /^@sentry\/server-utils\/orchestrion$/ }, async args => { + // The module-injected snippet imports `@sentry/server-utils` from INSIDE + // transformed `node_modules` files. Under isolated installs (pnpm) that + // bare specifier doesn't resolve from an instrumented package's location, + // so try esbuild's own resolution first (the `pluginData` marker stops the + // recursion back into this callback) and fall back to this package's own + // resolution. + build.onResolve({ filter: SNIPPET_IMPORT_SPECIFIER_FILTER }, async args => { if (args.pluginData === 'sentry-orchestrion-resolving') { return null; } diff --git a/packages/server-utils/src/orchestrion/bundler/moduleInjectedTransform.ts b/packages/server-utils/src/orchestrion/bundler/moduleInjectedTransform.ts index 781ba5fd8a0c..74e5b5ca71be 100644 --- a/packages/server-utils/src/orchestrion/bundler/moduleInjectedTransform.ts +++ b/packages/server-utils/src/orchestrion/bundler/moduleInjectedTransform.ts @@ -12,7 +12,11 @@ interface ProgramNode { body: Array<{ type: string; directive?: string }>; } -const DEFAULT_IMPORT_SPECIFIER = '@sentry/server-utils/orchestrion'; +// Where the injected snippet imports from: the `orchestrionModuleInjected` +// helper and the module's channel-subscriber factory both live on the main +// `@sentry/server-utils` entry, so a single import serves both. The ESM barrel +// tree-shakes to just the helper and the factories actually referenced. +const DEFAULT_IMPORT_SPECIFIER = '@sentry/server-utils'; /** * Entry-chunk banner that marks "the bundler plugin ran" for @@ -28,11 +32,11 @@ export const ORCHESTRION_BUNDLER_MARKER_BANNER = /** * Snippet injected into each instrumented module. It imports the * `orchestrionModuleInjected` helper — plus the module's channel-subscriber - * factory, when it has one — from `@sentry/server-utils/orchestrion` and calls - * the helper with the module's real name. The helper records the module on the - * global marker, stores the factory, and emits the `orchestrion.module-injected` - * client event, so it runs exactly when the module is evaluated — the moment - * its channels can start publishing. That per-module timing is what keeps + * factory, when it has one — from `@sentry/server-utils` and calls the helper + * with the module's real name. The helper records the module on the global + * marker, stores the factory, and emits the `orchestrion.module-injected` client + * event, so it runs exactly when the module is evaluated — the moment its + * channels can start publishing. That per-module timing is what keeps * subscriptions lazy (Node caps diagnostics channels in use at 1024). * * Importing the single named factory (rather than a central dispatch that pulls diff --git a/packages/server-utils/src/orchestrion/bundler/resolve.ts b/packages/server-utils/src/orchestrion/bundler/resolve.ts index 5412d9af6cb3..38817d1716cf 100644 --- a/packages/server-utils/src/orchestrion/bundler/resolve.ts +++ b/packages/server-utils/src/orchestrion/bundler/resolve.ts @@ -1,5 +1,18 @@ import { createRequire } from 'node:module'; +/** + * The specifier the module-injected snippet imports from — the + * `orchestrionModuleInjected` helper and the module's channel-subscriber factory + * both live on the main `@sentry/server-utils` entry. It is emitted INSIDE + * transformed `node_modules` files, where a bare specifier can't resolve from + * the importing package's location under isolated installs (pnpm), so every + * bundler plugin gives it build-time resolution help. + */ +export const SNIPPET_IMPORT_SPECIFIER = '@sentry/server-utils'; + +/** esbuild `onResolve` filter matching the snippet import specifier exactly. */ +export const SNIPPET_IMPORT_SPECIFIER_FILTER = /^@sentry\/server-utils$/; + // Both branches use `createRequire` (never alias the CJS `require`) so bundlers consuming this // module don't emit a "Critical dependency" warning. function getOrchestrionRequire(): ReturnType { diff --git a/packages/server-utils/src/orchestrion/bundler/rollup.ts b/packages/server-utils/src/orchestrion/bundler/rollup.ts index 104e7adaca12..4fd0dee7ab2e 100644 --- a/packages/server-utils/src/orchestrion/bundler/rollup.ts +++ b/packages/server-utils/src/orchestrion/bundler/rollup.ts @@ -3,7 +3,7 @@ import type { NormalizedInputOptions, Plugin, PluginContext } from 'rollup'; import { instrumentedModuleNames } from '../config'; import type { PluginOptions } from './options'; import { externalizedModulesWarning, orchestrionTransformOptions } from './options'; -import { resolveOrchestrionRuntimeRequest } from './resolve'; +import { resolveOrchestrionRuntimeRequest, SNIPPET_IMPORT_SPECIFIER } from './resolve'; /** * Rollup plugin that runs the orchestrion code transform on the bundled output. @@ -28,13 +28,13 @@ export function sentryOrchestrionPlugin(options: PluginOptions = {}): Plugin { return { ...codeTransformer(orchestrionTransformOptions(options)), - // The module-injected snippet imports `@sentry/server-utils/orchestrion` - // from INSIDE transformed `node_modules` files. Under isolated installs - // (pnpm) that bare specifier doesn't resolve from an instrumented package's - // location, so when normal resolution fails, fall back to this package's - // own resolution so the helper gets bundled from its real on-disk path. + // The module-injected snippet imports `@sentry/server-utils` from INSIDE + // transformed `node_modules` files. Under isolated installs (pnpm) that bare + // specifier doesn't resolve from an instrumented package's location, so when + // normal resolution fails, fall back to this package's own resolution so it + // gets bundled from its real on-disk path. async resolveId(this: PluginContext, source: string, importer: string | undefined) { - if (source !== '@sentry/server-utils/orchestrion') { + if (source !== SNIPPET_IMPORT_SPECIFIER) { return null; } const resolved = await this.resolve(source, importer, { skipSelf: true }); diff --git a/packages/server-utils/src/orchestrion/bundler/vite.ts b/packages/server-utils/src/orchestrion/bundler/vite.ts index 3e3a31662a16..033a571e90b1 100644 --- a/packages/server-utils/src/orchestrion/bundler/vite.ts +++ b/packages/server-utils/src/orchestrion/bundler/vite.ts @@ -3,7 +3,7 @@ import type { Plugin, ResolvedConfig } from 'vite'; import { instrumentedModuleNames } from '../config'; import type { PluginOptions } from './options'; import { externalEntryMatchesModule, externalizedModulesWarning, orchestrionTransformOptions } from './options'; -import { resolveOrchestrionRuntimeRequest } from './resolve'; +import { resolveOrchestrionRuntimeRequest, SNIPPET_IMPORT_SPECIFIER } from './resolve'; type TransformHandler = (this: unknown, code: string, id: string, opts?: { ssr?: boolean }) => unknown; @@ -59,14 +59,14 @@ export function sentryOrchestrionPlugin(options: PluginOptions = {}): Plugin { return { ...upstream, transform: ssrOnlyTransform(upstream.transform), - // The module-injected snippet imports `@sentry/server-utils/orchestrion` - // from INSIDE transformed `node_modules` files. Under isolated installs - // (pnpm) that bare specifier doesn't resolve from an instrumented package's - // location, so when normal resolution fails, fall back to this package's - // own resolution so the helper gets bundled from its real on-disk path. - // SSR-gated like the transform: the specifier only exists in SSR modules. + // The module-injected snippet imports `@sentry/server-utils` from INSIDE + // transformed `node_modules` files. Under isolated installs (pnpm) that bare + // specifier doesn't resolve from an instrumented package's location, so when + // normal resolution fails, fall back to this package's own resolution so it + // gets bundled from its real on-disk path. SSR-gated like the transform: the + // specifier only appears in SSR modules. async resolveId(source, importer, resolveOptions) { - if (source !== '@sentry/server-utils/orchestrion' || !resolveOptions?.ssr) { + if (source !== SNIPPET_IMPORT_SPECIFIER || !resolveOptions?.ssr) { return null; } const resolved = await this.resolve(source, importer, { ...resolveOptions, skipSelf: true }); diff --git a/packages/server-utils/src/orchestrion/bundler/webpack-loader.ts b/packages/server-utils/src/orchestrion/bundler/webpack-loader.ts index 34006c30483a..8cf8cf2df1f9 100644 --- a/packages/server-utils/src/orchestrion/bundler/webpack-loader.ts +++ b/packages/server-utils/src/orchestrion/bundler/webpack-loader.ts @@ -15,13 +15,13 @@ interface LoaderOptions { /** Fixed import specifier for the module-injected snippet. */ importSpecifier?: string; /** - * Absolute path to the `@sentry/server-utils/orchestrion` helper module. When - * set, the snippet imports a PER-FILE RELATIVE path to it: Turbopack rejects - * absolute-path imports ("server relative imports are not implemented yet"), - * and a bare specifier emitted inside a transformed package doesn't resolve - * from that package's location under isolated installs (pnpm). A relative - * specifier is resolved from the importing file and consumed entirely at - * build time. Takes precedence over `importSpecifier`. + * Absolute path to the `@sentry/server-utils` module the snippet imports from. + * When set, the snippet imports a PER-FILE RELATIVE path to it: Turbopack + * rejects absolute-path imports ("server relative imports are not implemented + * yet"), and a bare specifier emitted inside a transformed package doesn't + * resolve from that package's location under isolated installs (pnpm). A + * relative specifier is resolved from the importing file and consumed entirely + * at build time. Takes precedence over `importSpecifier`. */ importHelperPath?: string; } diff --git a/packages/server-utils/src/orchestrion/bundler/webpack.ts b/packages/server-utils/src/orchestrion/bundler/webpack.ts index 1e4cd2334bb6..4aed6df60460 100644 --- a/packages/server-utils/src/orchestrion/bundler/webpack.ts +++ b/packages/server-utils/src/orchestrion/bundler/webpack.ts @@ -3,11 +3,12 @@ import { SDK_VERSION } from '@sentry/core'; import type { Compiler } from 'webpack'; -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { instrumentedModuleNames, SENTRY_INSTRUMENTATIONS } from '../config'; import codeTransformerWebpack from '@apm-js-collab/code-transformer-bundler-plugins/webpack'; import type { PluginOptions } from './options'; -import { getOrchestrionLoaderPath, resolveOrchestrionRuntimeRequest } from './resolve'; +import { getOrchestrionLoaderPath, resolveOrchestrionRuntimeRequest, SNIPPET_IMPORT_SPECIFIER } from './resolve'; import { serializeInstrumentations as serializeInstrumentationsImpl } from '@apm-js-collab/code-transformer-bundler-plugins/core'; import type { AnyInstrumentationConfig, SerializableInstrumentationConfig } from '../apmTypes'; @@ -47,18 +48,17 @@ function externalizedWebpackModules(externals: unknown, moduleNames: string[]): ); } -const ORCHESTRION_HELPER_SPECIFIER = '@sentry/server-utils/orchestrion'; - -// The injected module-injected snippet imports `@sentry/server-utils/orchestrion` -// from INSIDE transformed `node_modules` files. Under isolated installs (pnpm) -// that bare specifier doesn't resolve from an instrumented package's location, -// so map it — exact-match only (the `$` suffix / `onlyModule`) — to this -// package's own resolution, in whichever alias form the config already uses. -// A user's own alias for the specifier is left untouched, and externals still -// win — webpack consults `externals` before resolving — so setups that -// externalize the runtime (e.g. Next.js) are unaffected. +// The injected module-injected snippet imports `@sentry/server-utils` from +// INSIDE transformed `node_modules` files. Under isolated installs (pnpm) that +// bare specifier doesn't resolve from an instrumented package's location, so map +// it — exact-match only (the `$` suffix / `onlyModule`) — to this package's own +// resolution, in whichever alias form the config already uses. Exact-match keeps +// it from swallowing its own subpaths (e.g. `/orchestrion/vite`), which resolve +// on their own. A user's own alias for the specifier is left untouched, and +// externals still win — webpack consults `externals` before resolving — so +// setups that externalize the runtime (e.g. Next.js) are unaffected. function addOrchestrionResolveAlias(compiler: Compiler): void { - const resolved = resolveOrchestrionRuntimeRequest(ORCHESTRION_HELPER_SPECIFIER); + const resolved = resolveOrchestrionRuntimeRequest(SNIPPET_IMPORT_SPECIFIER); if (!resolved) { return; } @@ -66,15 +66,15 @@ function addOrchestrionResolveAlias(compiler: Compiler): void { const resolveOptions = (compiler.options.resolve ??= {}); const alias = resolveOptions.alias; if (Array.isArray(alias)) { - if (!alias.some(entry => entry.name === ORCHESTRION_HELPER_SPECIFIER)) { - alias.push({ name: ORCHESTRION_HELPER_SPECIFIER, alias: resolved, onlyModule: true }); + if (!alias.some(entry => entry.name === SNIPPET_IMPORT_SPECIFIER)) { + alias.push({ name: SNIPPET_IMPORT_SPECIFIER, alias: resolved, onlyModule: true }); } return; } const aliasMap = (resolveOptions.alias = alias ?? {}); - if (!(`${ORCHESTRION_HELPER_SPECIFIER}$` in aliasMap) && !(ORCHESTRION_HELPER_SPECIFIER in aliasMap)) { - aliasMap[`${ORCHESTRION_HELPER_SPECIFIER}$`] = resolved; + if (!(`${SNIPPET_IMPORT_SPECIFIER}$` in aliasMap) && !(SNIPPET_IMPORT_SPECIFIER in aliasMap)) { + aliasMap[`${SNIPPET_IMPORT_SPECIFIER}$`] = resolved; } } diff --git a/packages/server-utils/src/orchestrion/config/amqplib.ts b/packages/server-utils/src/orchestrion/config/amqplib.ts index 769a68ab420e..e5e6e5439484 100644 --- a/packages/server-utils/src/orchestrion/config/amqplib.ts +++ b/packages/server-utils/src/orchestrion/config/amqplib.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // `amqplib` splits its API across three files: diff --git a/packages/server-utils/src/orchestrion/config/anthropic-ai.ts b/packages/server-utils/src/orchestrion/config/anthropic-ai.ts index a85b1aad6020..40cbdc515072 100644 --- a/packages/server-utils/src/orchestrion/config/anthropic-ai.ts +++ b/packages/server-utils/src/orchestrion/config/anthropic-ai.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const anthropicAiConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/channel-integration-definitions.ts b/packages/server-utils/src/orchestrion/config/channel-integration-definitions.ts index df7400104578..d674f464c143 100644 --- a/packages/server-utils/src/orchestrion/config/channel-integration-definitions.ts +++ b/packages/server-utils/src/orchestrion/config/channel-integration-definitions.ts @@ -2,7 +2,7 @@ * Build-time metadata mapping each instrumented package (orchestrion * `module.name`) to the channel-subscriber integration that consumes the * channels injected into it — by the `exportName` it is published under from - * `@sentry/server-utils/orchestrion`. + * `@sentry/server-utils`. * * Kept in a separate, factory-free module on purpose: the module-injected * transform (reachable from every orchestrion bundler plugin) reads this to @@ -10,7 +10,7 @@ * not drag any subscriber code — or its `@sentry/core` span machinery — into * the plugin's own build to do so. * - * `exportName` must be a named export of `@sentry/server-utils/orchestrion`. + * `exportName` must be a named export of `@sentry/server-utils`. * `modules` must match `module.name` values in `SENTRY_INSTRUMENTATIONS` — e.g. * `postgresIntegration` covers both `pg` and `pg-pool`, and `redisIntegration` * covers `redis`, `@redis/client` and `ioredis`. diff --git a/packages/server-utils/src/orchestrion/config/dataloader.ts b/packages/server-utils/src/orchestrion/config/dataloader.ts index cd1f0879bdc3..6969b20cf0eb 100644 --- a/packages/server-utils/src/orchestrion/config/dataloader.ts +++ b/packages/server-utils/src/orchestrion/config/dataloader.ts @@ -1,4 +1,4 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; // `dataloader` ships a single transpiled CommonJS `index.js`. Its class methods are emitted as // `_proto. = function () {}` (named function *expressions*), so they match on diff --git a/packages/server-utils/src/orchestrion/config/express.ts b/packages/server-utils/src/orchestrion/config/express.ts index 0e1c0aa86dc7..84ffb72b2c6f 100644 --- a/packages/server-utils/src/orchestrion/config/express.ts +++ b/packages/server-utils/src/orchestrion/config/express.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const expressConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/firebase.ts b/packages/server-utils/src/orchestrion/config/firebase.ts index 6787ccd171d3..c6af65cb0ea3 100644 --- a/packages/server-utils/src/orchestrion/config/firebase.ts +++ b/packages/server-utils/src/orchestrion/config/firebase.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // firebase 9+ ships firestore as `@firebase/firestore` (matches the OTel integration's range). Only the diff --git a/packages/server-utils/src/orchestrion/config/generic-pool.ts b/packages/server-utils/src/orchestrion/config/generic-pool.ts index d05ee3df0092..27ca2b16f6fc 100644 --- a/packages/server-utils/src/orchestrion/config/generic-pool.ts +++ b/packages/server-utils/src/orchestrion/config/generic-pool.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // Two shapes of `acquire`, both publishing to the same `orchestrion:generic-pool:acquire` channel: diff --git a/packages/server-utils/src/orchestrion/config/google-genai.ts b/packages/server-utils/src/orchestrion/config/google-genai.ts index 30b3f9c54c25..af8b416721bf 100644 --- a/packages/server-utils/src/orchestrion/config/google-genai.ts +++ b/packages/server-utils/src/orchestrion/config/google-genai.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // `@google/genai` ships one bundled file per module format and the matcher compares `filePath` exactly, diff --git a/packages/server-utils/src/orchestrion/config/graphql.ts b/packages/server-utils/src/orchestrion/config/graphql.ts index 07e509b5a313..d6eaabd2da5b 100644 --- a/packages/server-utils/src/orchestrion/config/graphql.ts +++ b/packages/server-utils/src/orchestrion/config/graphql.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // `parse`/`validate`/`execute` are top-level named `function` declarations in graphql's compiled diff --git a/packages/server-utils/src/orchestrion/config/hapi.ts b/packages/server-utils/src/orchestrion/config/hapi.ts index 90b8bde0085c..3acb5ca711b8 100644 --- a/packages/server-utils/src/orchestrion/config/hapi.ts +++ b/packages/server-utils/src/orchestrion/config/hapi.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const hapiConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/index.ts b/packages/server-utils/src/orchestrion/config/index.ts index 261eb32d993a..d105b967a72a 100644 --- a/packages/server-utils/src/orchestrion/config/index.ts +++ b/packages/server-utils/src/orchestrion/config/index.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { uniq } from '@sentry/core'; import { awsSdkConfig } from './aws-sdk'; @@ -121,3 +122,8 @@ export function withoutInstrumentedExternals( } return external.filter(entry => !moduleNames.some(name => entry === name || entry.startsWith(`${name}/`))); } + +// This is exported so that the nestjs package can use it to subscribe to the channels. +export { nestjsChannels } from './nestjs'; +// This is exported so that the remix package can use it to subscribe to the channels. +export { remixChannels } from './remix'; diff --git a/packages/server-utils/src/orchestrion/config/ioredis.ts b/packages/server-utils/src/orchestrion/config/ioredis.ts index edaa7f525985..0cb4a1688863 100644 --- a/packages/server-utils/src/orchestrion/config/ioredis.ts +++ b/packages/server-utils/src/orchestrion/config/ioredis.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const ioredisConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/kafkajs.ts b/packages/server-utils/src/orchestrion/config/kafkajs.ts index 56429345f8f6..3bdaec9ccbae 100644 --- a/packages/server-utils/src/orchestrion/config/kafkajs.ts +++ b/packages/server-utils/src/orchestrion/config/kafkajs.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const kafkajsConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/knex.ts b/packages/server-utils/src/orchestrion/config/knex.ts index 8c4c2d068563..4b68a62f77a6 100644 --- a/packages/server-utils/src/orchestrion/config/knex.ts +++ b/packages/server-utils/src/orchestrion/config/knex.ts @@ -1,4 +1,4 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; const MODULE_NAME = 'knex'; diff --git a/packages/server-utils/src/orchestrion/config/langchain.ts b/packages/server-utils/src/orchestrion/config/langchain.ts index 8d6df2950b5e..4697613a9448 100644 --- a/packages/server-utils/src/orchestrion/config/langchain.ts +++ b/packages/server-utils/src/orchestrion/config/langchain.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // `@langchain/*` packages ship dual CJS/ESM builds (`.cjs` for `require`, `.js` for `import`) and the diff --git a/packages/server-utils/src/orchestrion/config/langgraph.ts b/packages/server-utils/src/orchestrion/config/langgraph.ts index 9c66745ddb36..88cbefa5b4ff 100644 --- a/packages/server-utils/src/orchestrion/config/langgraph.ts +++ b/packages/server-utils/src/orchestrion/config/langgraph.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // `@langchain/langgraph` ships dual CJS/ESM builds (`.cjs` for `require`, `.js` for `import`) and the diff --git a/packages/server-utils/src/orchestrion/config/lru-memoizer.ts b/packages/server-utils/src/orchestrion/config/lru-memoizer.ts index b0cf7f37bca8..0e6c4ee36c18 100644 --- a/packages/server-utils/src/orchestrion/config/lru-memoizer.ts +++ b/packages/server-utils/src/orchestrion/config/lru-memoizer.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const lruMemoizerConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/mongodb.ts b/packages/server-utils/src/orchestrion/config/mongodb.ts index 6d5816c07475..101aaaf3e02d 100644 --- a/packages/server-utils/src/orchestrion/config/mongodb.ts +++ b/packages/server-utils/src/orchestrion/config/mongodb.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // The mongodb driver's command architecture changed across majors, mirrored in the vendored OTel diff --git a/packages/server-utils/src/orchestrion/config/mongoose.ts b/packages/server-utils/src/orchestrion/config/mongoose.ts index 2a9c8c1ee4eb..1d6deec70aa3 100644 --- a/packages/server-utils/src/orchestrion/config/mongoose.ts +++ b/packages/server-utils/src/orchestrion/config/mongoose.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // mongoose >= 9.7.0 publishes via its own `node:diagnostics_channel` tracing channels (handled by diff --git a/packages/server-utils/src/orchestrion/config/mysql.ts b/packages/server-utils/src/orchestrion/config/mysql.ts index 982619eadb1e..0fe3ec004369 100644 --- a/packages/server-utils/src/orchestrion/config/mysql.ts +++ b/packages/server-utils/src/orchestrion/config/mysql.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const mysqlConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/mysql2.ts b/packages/server-utils/src/orchestrion/config/mysql2.ts index 0dcb5e7067e4..09109b53ee18 100644 --- a/packages/server-utils/src/orchestrion/config/mysql2.ts +++ b/packages/server-utils/src/orchestrion/config/mysql2.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // Ports `@opentelemetry/instrumentation-mysql2` (which patches `query`/`execute` on the connection diff --git a/packages/server-utils/src/orchestrion/config/nestjs.ts b/packages/server-utils/src/orchestrion/config/nestjs.ts index fe52895cad55..5dc275aa6141 100644 --- a/packages/server-utils/src/orchestrion/config/nestjs.ts +++ b/packages/server-utils/src/orchestrion/config/nestjs.ts @@ -1,4 +1,4 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; /** * Wrap an instrumentation that targets nodes via a raw esquery selector diff --git a/packages/server-utils/src/orchestrion/config/openai.ts b/packages/server-utils/src/orchestrion/config/openai.ts index 1d087688c952..8227611b3615 100644 --- a/packages/server-utils/src/orchestrion/config/openai.ts +++ b/packages/server-utils/src/orchestrion/config/openai.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const openaiConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/pg.ts b/packages/server-utils/src/orchestrion/config/pg.ts index fcfb261dcbab..ea10c1bee4fb 100644 --- a/packages/server-utils/src/orchestrion/config/pg.ts +++ b/packages/server-utils/src/orchestrion/config/pg.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const pgConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/postgres.ts b/packages/server-utils/src/orchestrion/config/postgres.ts index 8dd899ac2fb7..b091bbde53ca 100644 --- a/packages/server-utils/src/orchestrion/config/postgres.ts +++ b/packages/server-utils/src/orchestrion/config/postgres.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; // postgres.js (`postgres` npm package, v3.x). Named after the npm package; diff --git a/packages/server-utils/src/orchestrion/config/redis.ts b/packages/server-utils/src/orchestrion/config/redis.ts index 7d5cc56839e4..54a695be096d 100644 --- a/packages/server-utils/src/orchestrion/config/redis.ts +++ b/packages/server-utils/src/orchestrion/config/redis.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const redisConfig = [ diff --git a/packages/server-utils/src/orchestrion/config/remix.ts b/packages/server-utils/src/orchestrion/config/remix.ts index 893efa781e5a..df89c6b5cc95 100644 --- a/packages/server-utils/src/orchestrion/config/remix.ts +++ b/packages/server-utils/src/orchestrion/config/remix.ts @@ -1,4 +1,4 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; // Four concepts, one channel each: // - `requestHandler` → the async handler returned by `createRequestHandler` (the server span) diff --git a/packages/server-utils/src/orchestrion/config/tedious.ts b/packages/server-utils/src/orchestrion/config/tedious.ts index a7c529331cf2..61af25ca2570 100644 --- a/packages/server-utils/src/orchestrion/config/tedious.ts +++ b/packages/server-utils/src/orchestrion/config/tedious.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; const MODULE_NAME = 'tedious'; diff --git a/packages/server-utils/src/orchestrion/config/vercel-ai.ts b/packages/server-utils/src/orchestrion/config/vercel-ai.ts index 6aa86beba558..07b0250d7ffc 100644 --- a/packages/server-utils/src/orchestrion/config/vercel-ai.ts +++ b/packages/server-utils/src/orchestrion/config/vercel-ai.ts @@ -1,4 +1,5 @@ -import type { InstrumentationConfig } from '..'; +import type { InstrumentationConfig } from '../apmTypes'; + import { getModuleNames } from './module-names'; export const vercelAiConfig = [ diff --git a/packages/server-utils/src/orchestrion/detect.ts b/packages/server-utils/src/orchestrion/detect.ts index 4545cbc56ed3..1466f008f66d 100644 --- a/packages/server-utils/src/orchestrion/detect.ts +++ b/packages/server-utils/src/orchestrion/detect.ts @@ -1,19 +1,5 @@ import { debug, GLOBAL_OBJ } from '@sentry/core'; -/** - * Whether orchestrion has injected the diagnostics channels into this process, - * either by the runtime `--import` hook / init-time registration (`runtime`) - * or a bundler plugin (`bundler`). Both injectors set a flag on the - * `globalThis.__SENTRY_ORCHESTRION__` marker. - * - * Use this to avoid wiring up channel-subscriber integrations when nothing - * will ever publish to those channels. - */ -export function isOrchestrionInjected(): boolean { - const marker = GLOBAL_OBJ.__SENTRY_ORCHESTRION__; - return !!(marker?.runtime || marker?.bundler || marker?.integrations); -} - /** * The module names (e.g. `mysql`, `@hapi/hapi`) orchestrion has already injected * into this process — from the runtime `--import` hook (`runtime`) and/or the diff --git a/packages/server-utils/src/orchestrion/index.ts b/packages/server-utils/src/orchestrion/index.ts deleted file mode 100644 index 0e6c926ad936..000000000000 --- a/packages/server-utils/src/orchestrion/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { amqplibIntegration } from '../integrations/amqplib'; -import { anthropicAIIntegration } from '../integrations/anthropic'; -import { awsIntegration } from '../integrations/aws-sdk'; -import { dataloaderIntegration } from '../integrations/dataloader'; -import { genericPoolIntegration } from '../integrations/generic-pool'; -import { googleGenAIIntegration } from '../integrations/google-genai'; -import { graphqlIntegration } from '../integrations/graphql'; -import { hapiIntegration } from '../integrations/hapi'; -import { koaIntegration } from '../integrations/koa'; -import { redisIntegration } from '../integrations/redis'; -import { kafkaIntegration } from '../integrations/kafkajs'; -import { knexIntegration } from '../integrations/knex'; -import { langChainIntegration } from '../integrations/langchain'; -import { langGraphIntegration } from '../integrations/langgraph'; -import { lruMemoizerIntegration } from '../integrations/lru-memoizer'; -import { mongoIntegration } from '../integrations/mongodb'; -import { mongooseIntegration } from '../integrations/mongoose'; -import { mysqlIntegration } from '../integrations/mysql'; -import { mysql2Integration } from '../integrations/mysql2'; -import { openAIIntegration } from '../integrations/openai'; -import { postgresIntegration } from '../integrations/postgres'; -import { postgresJsIntegration } from '../integrations/postgres-js'; -import { tediousIntegration } from '../integrations/tedious'; -import { vercelAIIntegration } from '../integrations/vercel-ai'; -import { expressIntegration } from '../integrations/express'; -import { firebaseIntegration } from '../integrations/firebase'; - -export { detectOrchestrionSetup, isOrchestrionInjected } from './detect'; -// The runtime target of the snippet the bundler transform splices into every -// instrumented module: records the module on the global marker (plus its -// subscriber factory, when it has one) and emits the module-injected event. -export { orchestrionModuleInjected } from './moduleInjected'; -// The `@nestjs/*` channel names live here alongside their transform config; the -// listener that subscribes to them lives in `@sentry/nestjs`, which imports this. -export { nestjsChannels } from './config/nestjs'; -// The remix channel names live here alongside their transform config; the -// listener that subscribes to them lives in `@sentry/remix`, which imports this. -export { remixChannels } from './config/remix'; -export { - amqplibIntegration, - anthropicAIIntegration, - awsIntegration, - dataloaderIntegration, - genericPoolIntegration, - googleGenAIIntegration, - graphqlIntegration, - hapiIntegration, - koaIntegration, - redisIntegration, - kafkaIntegration, - knexIntegration, - langChainIntegration, - langGraphIntegration, - lruMemoizerIntegration, - mongoIntegration, - mongooseIntegration, - mysqlIntegration, - mysql2Integration, - openAIIntegration, - postgresIntegration, - postgresJsIntegration, - tediousIntegration, - vercelAIIntegration, - expressIntegration, - firebaseIntegration, -}; -export type { InstrumentationConfig } from './apmTypes'; diff --git a/packages/server-utils/src/orchestrion/moduleInjected.ts b/packages/server-utils/src/utils/moduleInjected.ts similarity index 78% rename from packages/server-utils/src/orchestrion/moduleInjected.ts rename to packages/server-utils/src/utils/moduleInjected.ts index 0e78afe91e06..c1577c3931bb 100644 --- a/packages/server-utils/src/orchestrion/moduleInjected.ts +++ b/packages/server-utils/src/utils/moduleInjected.ts @@ -4,9 +4,14 @@ import { getClient, GLOBAL_OBJ } from '@sentry/core'; /** * Record a bundler-injected module and notify channel integrations. This is the * runtime target of the snippet the `tracingChannelImport` override splices - * into every instrumented module (see `bundler/moduleInjectedTransform.ts`), so - * it runs when that module is first evaluated — the moment its diagnostics - * channels can start publishing. + * into every instrumented module (see + * `orchestrion/bundler/moduleInjectedTransform.ts`), so it runs when that module + * is first evaluated — the moment its diagnostics channels can start publishing. + * + * Lives on the main `@sentry/server-utils` entry, not the orchestrion one: it is + * a plain runtime helper (reads the global marker, emits a client event) with no + * dependency on the orchestrion bundler/config code, and the injected snippet + * imports it from the same entry as the subscriber factories. * * It records the module name on the global orchestrion marker, stores the * module's channel-subscriber integration factory (when the module has one) diff --git a/packages/server-utils/test/graphql/utils.test.ts b/packages/server-utils/test/integrations/graphql/utils.test.ts similarity index 88% rename from packages/server-utils/test/graphql/utils.test.ts rename to packages/server-utils/test/integrations/graphql/utils.test.ts index d8e7a30b946d..a4cca667f4f2 100644 --- a/packages/server-utils/test/graphql/utils.test.ts +++ b/packages/server-utils/test/integrations/graphql/utils.test.ts @@ -1,7 +1,7 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; import * as core from '@sentry/core'; -import { collectGraphqlDocument } from '../../src/integrations/graphql/utils'; -import type { GraphqlDocumentNode } from '../../src/integrations/graphql/types'; +import { collectGraphqlDocument } from '../../../src/integrations/graphql/utils'; +import type { GraphqlDocumentNode } from '../../../src/integrations/graphql/types'; vi.spyOn(core, 'getClient'); diff --git a/packages/server-utils/test/integrations/tracing-channel/hapi-utils.test.ts b/packages/server-utils/test/integrations/hapi-utils.test.ts similarity index 95% rename from packages/server-utils/test/integrations/tracing-channel/hapi-utils.test.ts rename to packages/server-utils/test/integrations/hapi-utils.test.ts index 71c994f886d3..24fedaf14825 100644 --- a/packages/server-utils/test/integrations/tracing-channel/hapi-utils.test.ts +++ b/packages/server-utils/test/integrations/hapi-utils.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { getExtMetadata, getRouteMetadata } from '../../../src/integrations/hapi-utils'; +import { getExtMetadata, getRouteMetadata } from '../../src/integrations/hapi-utils'; describe('getRouteMetadata', () => { const route = { path: '/users/{id}', method: 'get' } as any; diff --git a/packages/server-utils/test/kafkajs.test.ts b/packages/server-utils/test/integrations/kafkajs.test.ts similarity index 94% rename from packages/server-utils/test/kafkajs.test.ts rename to packages/server-utils/test/integrations/kafkajs.test.ts index 4defd5823b4b..bfde55d7e568 100644 --- a/packages/server-utils/test/kafkajs.test.ts +++ b/packages/server-utils/test/integrations/kafkajs.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { isWrappedConsumerCallback, wrapEachBatch, wrapEachMessage } from '../src/integrations/kafkajs/consumer'; +import { isWrappedConsumerCallback, wrapEachBatch, wrapEachMessage } from '../../src/integrations/kafkajs/consumer'; // End-to-end span output (producer/consumer, error status, origins) is covered by the node integration // suite, which runs against a real broker in both OTel and orchestrion modes. This only covers the diff --git a/packages/server-utils/test/mysql2/mysql2-dc-subscriber.test.ts b/packages/server-utils/test/integrations/mysql2/mysql2-dc-subscriber.test.ts similarity index 99% rename from packages/server-utils/test/mysql2/mysql2-dc-subscriber.test.ts rename to packages/server-utils/test/integrations/mysql2/mysql2-dc-subscriber.test.ts index 79f2ece2ae53..2048edfb5155 100644 --- a/packages/server-utils/test/mysql2/mysql2-dc-subscriber.test.ts +++ b/packages/server-utils/test/integrations/mysql2/mysql2-dc-subscriber.test.ts @@ -25,7 +25,7 @@ import { MYSQL2_DC_CHANNEL_QUERY, type MySQL2TracingChannelFactory, subscribeMysql2DiagnosticChannels, -} from '../../src/integrations/mysql2/mysql2-dc-subscriber'; +} from '../../../src/integrations/mysql2/mysql2-dc-subscriber'; interface TestStore { scope: Scope; diff --git a/packages/server-utils/test/orchestrion/postgres-ignore-connect.test.ts b/packages/server-utils/test/integrations/postgres/postgres-ignore-connect.test.ts similarity index 96% rename from packages/server-utils/test/orchestrion/postgres-ignore-connect.test.ts rename to packages/server-utils/test/integrations/postgres/postgres-ignore-connect.test.ts index 990ea02db1a5..5254c7890e08 100644 --- a/packages/server-utils/test/orchestrion/postgres-ignore-connect.test.ts +++ b/packages/server-utils/test/integrations/postgres/postgres-ignore-connect.test.ts @@ -9,8 +9,8 @@ import { setAsyncContextStrategy, } from '@sentry/core'; import { afterAll, beforeAll, describe, expect, it } from 'vitest'; -import { postgresIntegration } from '../../src/orchestrion'; -import { CHANNELS } from '../../src/orchestrion/channels'; +import { postgresIntegration } from '../../../src/integrations/postgres'; +import { CHANNELS } from '../../../src/orchestrion/channels'; interface TestStore { scope: Scope; diff --git a/packages/server-utils/test/orchestrion/postgres.test.ts b/packages/server-utils/test/integrations/postgres/postgres.test.ts similarity index 98% rename from packages/server-utils/test/orchestrion/postgres.test.ts rename to packages/server-utils/test/integrations/postgres/postgres.test.ts index b0b529681dc9..192b4597665f 100644 --- a/packages/server-utils/test/orchestrion/postgres.test.ts +++ b/packages/server-utils/test/integrations/postgres/postgres.test.ts @@ -10,8 +10,8 @@ import { setAsyncContextStrategy, } from '@sentry/core'; import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, type MockInstance, vi } from 'vitest'; -import { postgresIntegration } from '../../src/orchestrion'; -import { CHANNELS } from '../../src/orchestrion/channels'; +import { postgresIntegration } from '../../../src/integrations/postgres'; +import { CHANNELS } from '../../../src/orchestrion/channels'; interface TestStore { scope: Scope; diff --git a/packages/server-utils/test/prisma.test.ts b/packages/server-utils/test/integrations/prisma.test.ts similarity index 92% rename from packages/server-utils/test/prisma.test.ts rename to packages/server-utils/test/integrations/prisma.test.ts index 8d887118b683..ef05eacc8b85 100644 --- a/packages/server-utils/test/prisma.test.ts +++ b/packages/server-utils/test/integrations/prisma.test.ts @@ -1,6 +1,6 @@ import { afterEach, describe, expect, it } from 'vitest'; -import { instrumentPrisma } from '../src/prisma'; -import type { TracingHelper } from '../src/prisma/types'; +import { instrumentPrisma } from '../../src/integrations/prisma'; +import type { TracingHelper } from '../../src/integrations/prisma/types'; type PrismaGlobal = typeof globalThis & { PRISMA_INSTRUMENTATION?: { helper?: TracingHelper }; diff --git a/packages/server-utils/test/redis/ioredis-channel-subscriber.test.ts b/packages/server-utils/test/integrations/redis/ioredis-channel-subscriber.test.ts similarity index 95% rename from packages/server-utils/test/redis/ioredis-channel-subscriber.test.ts rename to packages/server-utils/test/integrations/redis/ioredis-channel-subscriber.test.ts index 4ddcb5ac6082..94d2baec17ec 100644 --- a/packages/server-utils/test/redis/ioredis-channel-subscriber.test.ts +++ b/packages/server-utils/test/integrations/redis/ioredis-channel-subscriber.test.ts @@ -1,7 +1,7 @@ import type { Span } from '@sentry/core'; import * as SentryCore from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, type MockInstance, vi } from 'vitest'; -import { startIORedisCommandSpan } from '../../src/integrations/redis/ioredis-channel-subscriber'; +import { startIORedisCommandSpan } from '../../../src/integrations/redis/ioredis-channel-subscriber'; const CONNECTION = { host: 'localhost', port: 6379 }; diff --git a/packages/server-utils/test/redis/redis-cache.test.ts b/packages/server-utils/test/integrations/redis/redis-cache.test.ts similarity index 99% rename from packages/server-utils/test/redis/redis-cache.test.ts rename to packages/server-utils/test/integrations/redis/redis-cache.test.ts index 9b1e2d411705..7ea7f33bde90 100644 --- a/packages/server-utils/test/redis/redis-cache.test.ts +++ b/packages/server-utils/test/integrations/redis/redis-cache.test.ts @@ -7,7 +7,7 @@ import { REMOVE_COMMANDS, SET_COMMANDS, shouldConsiderForCache, -} from '../../src/integrations/redis/redis-cache'; +} from '../../../src/integrations/redis/redis-cache'; describe('redis cache', () => { describe('applyRedisCacheAttributes', () => { diff --git a/packages/server-utils/test/redis/redis-common.test.ts b/packages/server-utils/test/integrations/redis/redis-common.test.ts similarity index 95% rename from packages/server-utils/test/redis/redis-common.test.ts rename to packages/server-utils/test/integrations/redis/redis-common.test.ts index 86f51d5648b1..4c5732ab0708 100644 --- a/packages/server-utils/test/redis/redis-common.test.ts +++ b/packages/server-utils/test/integrations/redis/redis-common.test.ts @@ -5,7 +5,7 @@ */ import { describe, expect, it } from 'vitest'; -import { defaultDbStatementSerializer } from '../../src/integrations/redis/redis-statement-serializer'; +import { defaultDbStatementSerializer } from '../../../src/integrations/redis/redis-statement-serializer'; describe('defaultDbStatementSerializer()', () => { const testCases: Array<{ diff --git a/packages/server-utils/test/vercel-ai/skip-workers-ai.test.ts b/packages/server-utils/test/integrations/vercel-ai/skip-workers-ai.test.ts similarity index 92% rename from packages/server-utils/test/vercel-ai/skip-workers-ai.test.ts rename to packages/server-utils/test/integrations/vercel-ai/skip-workers-ai.test.ts index bbaedb7a979a..f4dc5f26d8ed 100644 --- a/packages/server-utils/test/vercel-ai/skip-workers-ai.test.ts +++ b/packages/server-utils/test/integrations/vercel-ai/skip-workers-ai.test.ts @@ -8,8 +8,8 @@ import { resolvedSyncPromise, } from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { WORKERS_AI_INTEGRATION_NAME } from '../../src/ai/workers-ai/constants'; -import { createSpanFromMessage } from '../../src/vercel-ai/vercel-ai-dc-subscriber'; +import { WORKERS_AI_INTEGRATION_NAME } from '../../../src/ai/workers-ai/constants'; +import { createSpanFromMessage } from '../../../src/integrations/vercel-ai/vercel-ai-dc-subscriber'; class TestClient extends Client { public eventFromException(): PromiseLike { diff --git a/packages/server-utils/test/orchestrion/bundler.test.ts b/packages/server-utils/test/orchestrion/bundler.test.ts index 83f7e49db37c..9f0bc947ceff 100644 --- a/packages/server-utils/test/orchestrion/bundler.test.ts +++ b/packages/server-utils/test/orchestrion/bundler.test.ts @@ -115,9 +115,9 @@ describe('sentryOrchestrionWebpackPlugin', () => { }); describe('snippet resolve alias', () => { - // The snippet's `@sentry/server-utils/orchestrion` import is emitted inside - // transformed node_modules files, where it doesn't resolve under isolated - // installs (pnpm) — the plugin maps it to this package's own resolution. + // The snippet's `@sentry/server-utils` import is emitted inside transformed + // node_modules files, where it doesn't resolve under isolated installs + // (pnpm) — the plugin maps it to this package's own resolution. function applyWithResolve(resolve: unknown): { alias?: unknown } { const options = { externals: undefined, resolve } as { resolve?: { alias?: unknown } }; const compiler = { @@ -131,7 +131,7 @@ describe('sentryOrchestrionWebpackPlugin', () => { it('adds an exact-match alias to object-form (and absent) alias config', () => { const { alias } = applyWithResolve(undefined); - const target = (alias as Record)['@sentry/server-utils/orchestrion$']; + const target = (alias as Record)['@sentry/server-utils$']; expect(target).toBeDefined(); expect(isAbsolute(target!)).toBe(true); @@ -144,18 +144,18 @@ describe('sentryOrchestrionWebpackPlugin', () => { expect(alias).toEqual([ existing, { - name: '@sentry/server-utils/orchestrion', - alias: expect.stringMatching(/orchestrion/), + name: '@sentry/server-utils', + alias: expect.stringMatching(/server-utils/), onlyModule: true, }, ]); }); it('leaves an existing user alias for the specifier untouched', () => { - const { alias: objectAlias } = applyWithResolve({ alias: { '@sentry/server-utils/orchestrion': '/user' } }); - expect(objectAlias).toEqual({ '@sentry/server-utils/orchestrion': '/user' }); + const { alias: objectAlias } = applyWithResolve({ alias: { '@sentry/server-utils': '/user' } }); + expect(objectAlias).toEqual({ '@sentry/server-utils': '/user' }); - const userEntry = { name: '@sentry/server-utils/orchestrion', alias: '/user' }; + const userEntry = { name: '@sentry/server-utils', alias: '/user' }; const { alias: arrayAlias } = applyWithResolve({ alias: [userEntry] }); expect(arrayAlias).toEqual([userEntry]); }); @@ -225,23 +225,19 @@ describe('sentryOrchestrionPlugin (vite)', () => { ) => Promise; const resolve = vi.fn().mockResolvedValue(null); - await expect( - resolveId.call({ resolve }, '@sentry/server-utils/orchestrion', '/x.js', { ssr: false }), - ).resolves.toBeNull(); + await expect(resolveId.call({ resolve }, '@sentry/server-utils', '/x.js', { ssr: false })).resolves.toBeNull(); expect(resolve).not.toHaveBeenCalled(); // Normal resolution wins when it succeeds. resolve.mockResolvedValueOnce({ id: '/resolved.js' }); - await expect( - resolveId.call({ resolve }, '@sentry/server-utils/orchestrion', '/x.js', { ssr: true }), - ).resolves.toEqual({ + await expect(resolveId.call({ resolve }, '@sentry/server-utils', '/x.js', { ssr: true })).resolves.toEqual({ id: '/resolved.js', }); // When it fails (pnpm isolation), fall back to this package's own resolution. - const fallback = await resolveId.call({ resolve }, '@sentry/server-utils/orchestrion', '/x.js', { ssr: true }); + const fallback = await resolveId.call({ resolve }, '@sentry/server-utils', '/x.js', { ssr: true }); expect(typeof fallback).toBe('string'); - expect(fallback).toContain('orchestrion'); + expect(fallback).toContain('server-utils'); }); }); @@ -290,7 +286,7 @@ describe('resolveOrchestrionRuntimeRequest', () => { it.each([ // Self-references — resolve through this package's own exports map to the CJS build. '@sentry/server-utils/orchestrion/register', - '@sentry/server-utils/orchestrion', + '@sentry/server-utils/orchestrion/config', // Dependencies of this package, including subpaths only reachable from its location. '@apm-js-collab/tracing-hooks', '@apm-js-collab/tracing-hooks/hook.mjs', diff --git a/packages/server-utils/test/orchestrion/detect.test.ts b/packages/server-utils/test/orchestrion/detect.test.ts deleted file mode 100644 index 972cc7b0af37..000000000000 --- a/packages/server-utils/test/orchestrion/detect.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { GLOBAL_OBJ } from '@sentry/core'; -import { afterEach, beforeEach, describe, expect, it } from 'vitest'; -import { isOrchestrionInjected } from '../../src/orchestrion/detect'; - -describe('isOrchestrionInjected', () => { - beforeEach(() => { - delete GLOBAL_OBJ.__SENTRY_ORCHESTRION__; - }); - - afterEach(() => { - delete GLOBAL_OBJ.__SENTRY_ORCHESTRION__; - }); - - it('is false when no marker exists', () => { - expect(isOrchestrionInjected()).toBe(false); - }); - - it.each([ - ['runtime', { runtime: [] }], - ['bundler array', { bundler: ['mysql'] }], - ['bundler true', { bundler: true }], - ['integrations', { integrations: new Map() }], - ] as const)('is true when %s injection is present', (_label, marker) => { - // Cast through `unknown`: rows are `as const` (readonly) and `bundler: true` - // is a legacy runtime shape the marker type no longer spells out. - GLOBAL_OBJ.__SENTRY_ORCHESTRION__ = marker as unknown as typeof GLOBAL_OBJ.__SENTRY_ORCHESTRION__; - expect(isOrchestrionInjected()).toBe(true); - }); -}); diff --git a/packages/server-utils/test/orchestrion/moduleInjectedTransform.test.ts b/packages/server-utils/test/orchestrion/moduleInjectedTransform.test.ts index 57817b569a08..6276bd422772 100644 --- a/packages/server-utils/test/orchestrion/moduleInjectedTransform.test.ts +++ b/packages/server-utils/test/orchestrion/moduleInjectedTransform.test.ts @@ -28,8 +28,10 @@ describe('channel integration definitions', () => { expect(subscriberExportForModule('not-a-package')).toBeUndefined(); }); - it('references only real named exports of @sentry/server-utils/orchestrion', async () => { - const barrel = await import('../../src/orchestrion/index'); + it('references only real named exports of @sentry/server-utils', async () => { + // The injected snippet imports each factory from `@sentry/server-utils` + // (the `DEFAULT_IMPORT_SPECIFIER`), so the export must exist on that entry. + const barrel = await import('../../src/index'); for (const { exportName } of CHANNEL_INTEGRATION_DEFINITIONS) { expect(typeof (barrel as Record)[exportName]).toBe('function'); } @@ -58,9 +60,10 @@ describe('module-injected transform', () => { expect(result).not.toBeNull(); expect(result!.code.split('\n')[0]).toContain("'use strict'"); - // Imports ONLY the mysql factory plus the generic helper, from a single require. + // Imports the helper and ONLY the mysql factory, from a single require of + // the main entry. expect(result!.code).toMatch( - /const\s*\{\s*orchestrionModuleInjected,\s*mysqlIntegration\s*\}\s*=\s*require\(["']@sentry\/server-utils\/orchestrion["']\)/, + /const\s*\{\s*orchestrionModuleInjected,\s*mysqlIntegration\s*\}\s*=\s*require\(["']@sentry\/server-utils["']\)/, ); // The helper is called with the REAL module name, so no reverse lookup is // needed at runtime and the lazy-subscription event matches what channel @@ -83,7 +86,7 @@ describe('module-injected transform', () => { expect(result).not.toBeNull(); expect(result!.code).toMatch( - /import\s*\{\s*orchestrionModuleInjected,\s*postgresIntegration\s*\}\s*from\s*["']@sentry\/server-utils\/orchestrion["']/, + /import\s*\{\s*orchestrionModuleInjected,\s*postgresIntegration\s*\}\s*from\s*["']@sentry\/server-utils["']/, ); expect(result!.code).not.toContain('@sentry/core'); expect(result!.code).toContain('orchestrionModuleInjected("pg", postgresIntegration)'); @@ -106,8 +109,9 @@ describe('module-injected transform', () => { const result = t.transform('function doWork(){ return 1; }\n', join(root, 'node_modules/my-lib/lib/index.js')); expect(result).not.toBeNull(); + // No factory for this module, so the snippet imports only the helper. expect(result!.code).toMatch( - /const\s*\{\s*orchestrionModuleInjected\s*\}\s*=\s*require\(["']@sentry\/server-utils\/orchestrion["']\)/, + /const\s*\{\s*orchestrionModuleInjected\s*\}\s*=\s*require\(["']@sentry\/server-utils["']\)/, ); expect(result!.code).toContain('orchestrionModuleInjected("my-lib")'); }); @@ -127,7 +131,7 @@ describe('module-injected transform', () => { it('honors a custom import specifier (Turbopack passes an absolute path)', () => { const t = createCodeTransformer({ ...orchestrionTransformOptions({}), - customTransforms: moduleInjectedTransforms('/abs/path/to/orchestrion/index.js'), + customTransforms: moduleInjectedTransforms('/abs/path/to/server-utils/index.js'), }); const result = t.transform( "'use strict';\nfunction Connection(){}\nConnection.prototype.query = function query(sql, cb){ return cb(); };\n", @@ -135,7 +139,11 @@ describe('module-injected transform', () => { ); expect(result).not.toBeNull(); - expect(result!.code).toContain('require("/abs/path/to/orchestrion/index.js")'); - expect(result!.code).not.toContain('require("@sentry/server-utils/orchestrion")'); + // The helper and factory import resolves against the override, not the + // default bare specifier. + expect(result!.code).toMatch( + /const\s*\{\s*orchestrionModuleInjected,\s*mysqlIntegration\s*\}\s*=\s*require\("\/abs\/path\/to\/server-utils\/index\.js"\)/, + ); + expect(result!.code).not.toContain('require("@sentry/server-utils")'); }); }); diff --git a/packages/server-utils/test/orchestrion/webpack-loader.test.ts b/packages/server-utils/test/orchestrion/webpack-loader.test.ts index ca56a6993730..5e7e20eb2365 100644 --- a/packages/server-utils/test/orchestrion/webpack-loader.test.ts +++ b/packages/server-utils/test/orchestrion/webpack-loader.test.ts @@ -62,7 +62,7 @@ describe('orchestrion webpack/Turbopack loader', () => { expect(error).toBeNull(); expect(code).toContain('orchestrion:mysql:query'); expect(code).toMatch( - /const\s*\{\s*orchestrionModuleInjected,\s*mysqlIntegration\s*\}\s*=\s*require\(["']@sentry\/server-utils\/orchestrion["']\)/, + /const\s*\{\s*orchestrionModuleInjected,\s*mysqlIntegration\s*\}\s*=\s*require\(["']@sentry\/server-utils["']\)/, ); expect(code).toContain('orchestrionModuleInjected("mysql", mysqlIntegration)'); }); @@ -70,24 +70,24 @@ describe('orchestrion webpack/Turbopack loader', () => { it('honors a fixed importSpecifier option', () => { const { code } = runLoader(join(root, 'node_modules/mysql/lib/Connection.js'), MYSQL_CONNECTION_SOURCE, { instrumentations, - importSpecifier: 'my-custom-orchestrion-helper', + importSpecifier: 'my-custom-server-utils', }); - expect(code).toContain('require("my-custom-orchestrion-helper")'); - expect(code).not.toContain('require("@sentry/server-utils/orchestrion")'); + expect(code).toContain('require("my-custom-server-utils")'); + expect(code).not.toContain('require("@sentry/server-utils")'); }); it('derives a per-file relative specifier from importHelperPath (Turbopack)', () => { // Turbopack rejects absolute-path imports and bare specifiers that don't - // resolve from the importing file, so the snippet must import relatively. - const importHelperPath = join(root, 'node_modules/@sentry/server-utils/build/cjs/orchestrion/index.js'); + // resolve from the importing file, so the snippet import must be relative. + const importHelperPath = join(root, 'node_modules/@sentry/server-utils/build/cjs/index.js'); const { code } = runLoader(join(root, 'node_modules/mysql/lib/Connection.js'), MYSQL_CONNECTION_SOURCE, { instrumentations, importHelperPath, }); - expect(code).toContain('require("../../@sentry/server-utils/build/cjs/orchestrion/index.js")'); - expect(code).not.toContain('require("@sentry/server-utils/orchestrion")'); + expect(code).toContain('require("../../@sentry/server-utils/build/cjs/index.js")'); + expect(code).not.toContain('require("@sentry/server-utils")'); }); it('passes through files of packages that are not instrumented', () => { diff --git a/packages/server-utils/test/orchestrion/moduleInjected.test.ts b/packages/server-utils/test/utils/moduleInjected.test.ts similarity index 97% rename from packages/server-utils/test/orchestrion/moduleInjected.test.ts rename to packages/server-utils/test/utils/moduleInjected.test.ts index d64fda3d60a5..3970037fb1fb 100644 --- a/packages/server-utils/test/orchestrion/moduleInjected.test.ts +++ b/packages/server-utils/test/utils/moduleInjected.test.ts @@ -1,7 +1,7 @@ import type { Client, Integration } from '@sentry/core'; import { getCurrentScope, GLOBAL_OBJ } from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { orchestrionModuleInjected } from '../../src/orchestrion/moduleInjected'; +import { orchestrionModuleInjected } from '../../src/utils/moduleInjected'; describe('orchestrionModuleInjected', () => { const factory = (name: string) => (): Integration => ({ name, setupOnce: () => undefined });