diff --git a/packages/astro/src/server/middleware.ts b/packages/astro/src/server/middleware.ts index 34f0921c9905..54c9fdf0dbb9 100644 --- a/packages/astro/src/server/middleware.ts +++ b/packages/astro/src/server/middleware.ts @@ -2,7 +2,6 @@ import type { Span, SpanAttributes } from '@sentry/core'; import { addNonEnumerableProperty, - flushIfServerless, getIsolationScope, getRootSpan, objectify, @@ -11,6 +10,7 @@ import { stripUrlQueryAndFragment, winterCGRequestToRequestData, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { captureException, continueTrace, diff --git a/packages/bun/package.json b/packages/bun/package.json index 737cda5c107a..a01944e05e8b 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -39,6 +39,7 @@ "access": "public" }, "dependencies": { + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0", "@sentry/node": "10.54.0" }, diff --git a/packages/bun/src/client.ts b/packages/bun/src/client.ts index fceef3e472bc..0b6e776feec4 100644 --- a/packages/bun/src/client.ts +++ b/packages/bun/src/client.ts @@ -1,5 +1,6 @@ -import type { ServerRuntimeClientOptions } from '@sentry/core'; -import { applySdkMetadata, ServerRuntimeClient } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; +import { applySdkMetadata } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import * as os from 'os'; import type { BunClientOptions } from './types'; diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index e3006a8bed52..e7ddb0339b0a 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -50,6 +50,7 @@ }, "dependencies": { "@opentelemetry/api": "^1.9.1", + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0" }, "peerDependencies": { diff --git a/packages/cloudflare/src/client.ts b/packages/cloudflare/src/client.ts index 80c6a9b0322c..5ed27013dcdd 100644 --- a/packages/cloudflare/src/client.ts +++ b/packages/cloudflare/src/client.ts @@ -1,5 +1,7 @@ -import type { ClientOptions, Options, ServerRuntimeClientOptions } from '@sentry/core'; -import { applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core'; +import type { ClientOptions, Options } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; +import { applySdkMetadata, debug } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import { DEBUG_BUILD } from './debug-build'; import type { makeFlushLock } from './flush'; import type { CloudflareTransportOptions } from './transport'; diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index fb4a9bf84882..5397d8d1d4a7 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -86,19 +86,16 @@ export { moduleMetadataIntegration, supabaseIntegration, instrumentSupabaseClient, - instrumentPostgresJsSql, zodErrorsIntegration, consoleIntegration, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, - trpcMiddleware, spanToJSON, spanToTraceHeader, spanToBaggageHeader, updateSpanName, - wrapMcpServerWithSentry, consoleLoggingIntegration, createConsolaReporter, createLangChainCallbackHandler, @@ -112,6 +109,11 @@ export { instrumentLangGraph, instrumentCreateReactAgent, } from '@sentry/core'; +export { + instrumentPostgresJsSql, + trpcMiddleware, + wrapMcpServerWithSentry, +} from '@sentry-internal/server-utils'; export { withSentry } from './withSentry'; export { instrumentDurableObjectWithSentry } from './durableobject'; diff --git a/packages/cloudflare/src/vendor/stacktrace.ts b/packages/cloudflare/src/vendor/stacktrace.ts index 64a82a77ee32..3e8073f24c64 100644 --- a/packages/cloudflare/src/vendor/stacktrace.ts +++ b/packages/cloudflare/src/vendor/stacktrace.ts @@ -22,7 +22,8 @@ // SOFTWARE. import type { StackLineParser, StackLineParserFn, StackParser } from '@sentry/core'; -import { basename, createStackParser, nodeStackLineParser } from '@sentry/core'; +import { basename, createStackParser } from '@sentry/core'; +import { nodeStackLineParser } from '@sentry-internal/server-utils'; type GetModuleFn = (filename: string | undefined) => string | undefined; diff --git a/packages/core/package.json b/packages/core/package.json index 5285e3857a65..847ab1f02c18 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -12,25 +12,13 @@ "files": [ "/build", "browser.js", - "browser.d.ts", - "server.js", - "server.d.ts" + "browser.d.ts" ], "main": "build/cjs/index.js", "module": "build/esm/index.js", "types": "build/types/index.d.ts", "exports": { "./package.json": "./package.json", - "./server": { - "import": { - "types": "./build/types/server.d.ts", - "default": "./build/esm/server.js" - }, - "require": { - "types": "./build/types/server.d.ts", - "default": "./build/cjs/server.js" - } - }, "./browser": { "import": { "types": "./build/types/browser.d.ts", @@ -59,9 +47,6 @@ ], "browser": [ "build/types-ts3.8/browser.d.ts" - ], - "server": [ - "build/types-ts3.8/server.d.ts" ] } }, @@ -92,40 +77,7 @@ "extends": "../../package.json" }, "sideEffects": false, - "dependencies": { - "@sentry-internal/server-utils": "10.54.0" - }, "devDependencies": { "zod": "^3.24.1" - }, - "nx": { - "targets": { - "build:transpile": { - "dependsOn": [] - }, - "build:types": { - "dependsOn": [] - }, - "build:dev": { - "dependsOn": [] - }, - "build:tarball": { - "dependsOn": [ - "build:transpile", - "build:types" - ] - }, - "test:unit": { - "dependsOn": [ - "build:transpile", - "build:types" - ] - }, - "lint": { - "dependsOn": [ - "build:types" - ] - } - } } } diff --git a/packages/core/rollup.npm.config.mjs b/packages/core/rollup.npm.config.mjs index 610de17fadf3..20aab9c90fa5 100644 --- a/packages/core/rollup.npm.config.mjs +++ b/packages/core/rollup.npm.config.mjs @@ -39,6 +39,6 @@ const settings = { export default makeNPMConfigVariants( makeBaseNPMConfig({ ...settings, - entrypoints: ['src/index.ts', 'src/server.ts', 'src/browser.ts'], + entrypoints: ['src/index.ts', 'src/browser.ts'], }), ); diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 3e40ce629795..5d280809d8eb 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,3 +1,2 @@ export * from './shared-exports'; -export * from './server-exports'; export * from './browser-exports'; diff --git a/packages/core/src/shared-exports.ts b/packages/core/src/shared-exports.ts index 7d36db3dd168..de23353d7148 100644 --- a/packages/core/src/shared-exports.ts +++ b/packages/core/src/shared-exports.ts @@ -156,8 +156,9 @@ export * as logger from './logs/public-api'; export { consoleLoggingIntegration } from './logs/console-integration'; export { _INTERNAL_captureMetric, - _INTERNAL_flushMetricsBuffer, _INTERNAL_captureSerializedMetric, + _INTERNAL_flushMetricsBuffer, + _INTERNAL_getMetricBuffer, } from './metrics/internal'; export * as metrics from './metrics/public-api'; export type { MetricOptions } from './metrics/public-api'; @@ -543,3 +544,11 @@ export { safeMathRandom as _INTERNAL_safeMathRandom, safeDateNow as _INTERNAL_safeDateNow, } from './utils/randomSafeContext'; + +// Exposed so that `@sentry-internal/server-utils` can build `ServerRuntimeClient` +// on top of `Client` without copying these internal helpers. +export { DEFAULT_TRANSPORT_BUFFER_SIZE } from './transports/base'; +export { addUserAgentToTransportHeaders } from './transports/userAgent'; +export { _getTraceInfoFromScope } from './utils/trace-info'; +export { safeUnref as _INTERNAL_safeUnref } from './utils/timer'; +export { isNodeEnv, loadModule } from './utils/node'; diff --git a/packages/core/src/types/options.ts b/packages/core/src/types/options.ts index e6d5714adff0..fdb2c9e37d2c 100644 --- a/packages/core/src/types/options.ts +++ b/packages/core/src/types/options.ts @@ -12,95 +12,6 @@ import type { StackLineParser, StackParser } from './stacktrace'; import type { TracePropagationTargets } from './tracing'; import type { BaseTransportOptions, Transport } from './transport'; -/** - * Base options for WinterTC-compatible server-side JavaScript runtimes. - * This interface contains common configuration options shared between - * SDKs. - */ -export interface ServerRuntimeOptions { - /** - * List of strings/regex controlling to which outgoing requests - * the SDK will attach tracing headers. - * - * By default the SDK will attach those headers to all outgoing - * requests. If this option is provided, the SDK will match the - * request URL of outgoing requests against the items in this - * array, and only attach tracing headers if a match was found. - * - * @example - * ```js - * Sentry.init({ - * tracePropagationTargets: ['api.site.com'], - * }); - * ``` - */ - tracePropagationTargets?: TracePropagationTargets; - - /** - * Sets an optional server name (device name). - * - * This is useful for identifying which server or instance is sending events. - */ - serverName?: string; - - /** - * If you use Spotlight by Sentry during development, use - * this option to forward captured Sentry events to Spotlight. - * - * Either set it to true, or provide a specific Spotlight Sidecar URL. - * - * More details: https://spotlightjs.com/ - * - * IMPORTANT: Only set this option to `true` while developing, not in production! - */ - spotlight?: boolean | string; - - /** - * If set to `false`, the SDK will not automatically detect the `serverName`. - * - * This is useful if you are using the SDK in a CLI app or Electron where the - * hostname might be considered PII. - * - * @default true - */ - includeServerName?: boolean; - - /** - * By default, the SDK will try to identify problems with your instrumentation setup and warn you about it. - * If you want to disable these warnings, set this to `true`. - */ - disableInstrumentationWarnings?: boolean; - - /** - * Controls how many milliseconds to wait before shutting down. The default is 2 seconds. Setting this too low can cause - * problems for sending events from command line applications. Setting it too - * high can cause the application to block for users with network connectivity - * problems. - */ - shutdownTimeout?: number; - - /** - * Configures in which interval client reports will be flushed. Defaults to `60_000` (milliseconds). - */ - clientReportFlushInterval?: number; - - /** - * The max. duration in seconds that the SDK will wait for parent spans to be finished before discarding a span. - * The SDK will automatically clean up spans that have no finished parent after this duration. - * This is necessary to prevent memory leaks in case of parent spans that are never finished or otherwise dropped/missing. - * However, if you have very long-running spans in your application, a shorter duration might cause spans to be discarded too early. - * In this case, you can increase this duration to a value that fits your expected data. - * - * Defaults to 300 seconds (5 minutes). - */ - maxSpanWaitDuration?: number; - - /** - * Callback that is executed when a fatal global error occurs. - */ - onFatalError?(this: void, error: Error): void; -} - /** * Allowed attribute value matchers in `ignoreSpans` filters. * String span attributes use pattern matching (substring or RegExp). diff --git a/packages/core/src/utils/anr.ts b/packages/core/src/utils/anr.ts index ad6db13a1bf9..21d1fc6e1ae1 100644 --- a/packages/core/src/utils/anr.ts +++ b/packages/core/src/utils/anr.ts @@ -1,6 +1,6 @@ -import type { StackFrame } from '../types/stackframe'; +import type { StackFrame } from '@sentry/core'; +import { UNKNOWN_FUNCTION } from '@sentry/core'; import { filenameIsInApp } from './node-stack-trace'; -import { UNKNOWN_FUNCTION } from './stacktrace'; type WatchdogReturn = { /** Resets the watchdog timer */ diff --git a/packages/core/src/utils/flushIfServerless.ts b/packages/core/src/utils/flushIfServerless.ts index 5ffd86612243..6491cc5af277 100644 --- a/packages/core/src/utils/flushIfServerless.ts +++ b/packages/core/src/utils/flushIfServerless.ts @@ -1,7 +1,5 @@ -import { flush } from '../exports'; -import { debug } from './debug-logger'; +import { debug, flush, GLOBAL_OBJ } from '@sentry/core'; import { vercelWaitUntil } from './vercelWaitUntil'; -import { GLOBAL_OBJ } from './worldwide'; type MinimalCloudflareContext = { // eslint-disable-next-line @typescript-eslint/no-explicit-any diff --git a/packages/core/src/utils/node-stack-trace.ts b/packages/core/src/utils/node-stack-trace.ts index 3861a84bdeba..7476c997f609 100644 --- a/packages/core/src/utils/node-stack-trace.ts +++ b/packages/core/src/utils/node-stack-trace.ts @@ -21,11 +21,22 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN // THE SOFTWARE. -import type { StackLineParser, StackLineParserFn } from '../types/stacktrace'; -import { normalizeStackTracePath, UNKNOWN_FUNCTION } from './stacktrace'; +import type { StackLineParser, StackLineParserFn } from '@sentry/core'; +import { UNKNOWN_FUNCTION } from '@sentry/core'; export type GetModuleFn = (filename: string | undefined) => string | undefined; +// Vendored from `@sentry/core`'s private `utils/stacktrace.ts`. Strips a leading +// `file://` and the extra leading slash on Windows paths so stack frame +// filenames match the runtime paths users care about. +function normalizeStackTracePath(path: string | undefined): string | undefined { + let filename = path?.startsWith('file://') ? path.slice(7) : path; + if (filename?.match(/\/[A-Z]:/)) { + filename = filename.slice(1); + } + return filename; +} + /** * Does this filename look like it's part of the app code? */ diff --git a/packages/core/src/utils/vercelWaitUntil.ts b/packages/core/src/utils/vercelWaitUntil.ts index 32d801a6723c..76d26ecbd5a0 100644 --- a/packages/core/src/utils/vercelWaitUntil.ts +++ b/packages/core/src/utils/vercelWaitUntil.ts @@ -1,4 +1,4 @@ -import { GLOBAL_OBJ } from './worldwide'; +import { GLOBAL_OBJ } from '@sentry/core'; declare const EdgeRuntime: string | undefined; diff --git a/packages/core/test/lib/integrations/metadata.test.ts b/packages/core/test/lib/integrations/metadata.test.ts index 4063662de9f4..507deed8074f 100644 --- a/packages/core/test/lib/integrations/metadata.test.ts +++ b/packages/core/test/lib/integrations/metadata.test.ts @@ -5,14 +5,24 @@ import { createTransport, GLOBAL_OBJ, moduleMetadataIntegration, - nodeStackLineParser, parseEnvelope, setCurrentClient, + type StackLineParser, } from '../../../src'; import type { Event } from '../../../src/types/event'; + +// Minimal Node-style stack-line parser. Sufficient for the `Error().stack` lines +// generated below; the full Node parser now lives in `@sentry-internal/server-utils`. +const nodeStackLineFixture: StackLineParser = [ + 90, + (line: string) => { + const m = line.match(/at (?:async )?(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?/); + return m ? { function: m[1], filename: m[2], lineno: +m[3]!, colno: +m[4]! } : undefined; + }, +]; import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; -const stackParser = createStackParser(nodeStackLineParser()); +const stackParser = createStackParser(nodeStackLineFixture); const stack = new Error().stack || ''; diff --git a/packages/core/test/lib/integrations/third-party-errors-filter.test.ts b/packages/core/test/lib/integrations/third-party-errors-filter.test.ts index 7bb5120d2b88..99cd40710314 100644 --- a/packages/core/test/lib/integrations/third-party-errors-filter.test.ts +++ b/packages/core/test/lib/integrations/third-party-errors-filter.test.ts @@ -1,9 +1,9 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import type { StackLineParser } from '../../../src'; import type { Client } from '../../../src/client'; import { thirdPartyErrorFilterIntegration } from '../../../src/integrations/third-party-errors-filter'; import { addMetadataToStackFrames } from '../../../src/metadata'; import type { Event } from '../../../src/types/event'; -import { nodeStackLineParser } from '../../../src/utils/node-stack-trace'; import { createStackParser } from '../../../src/utils/stacktrace'; import { GLOBAL_OBJ } from '../../../src/utils/worldwide'; @@ -12,7 +12,16 @@ function clone(data: T): T { } const stack = new Error().stack || ''; -const stackParser = createStackParser(nodeStackLineParser()); +// Minimal Node-style stack-line parser. Sufficient for the `Error().stack` lines +// parsed below; the full Node parser now lives in `@sentry-internal/server-utils`. +const nodeStackLineFixture: StackLineParser = [ + 90, + (line: string) => { + const m = line.match(/at (?:async )?(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?/); + return m ? { function: m[1], filename: m[2], lineno: +m[3]!, colno: +m[4]! } : undefined; + }, +]; +const stackParser = createStackParser(nodeStackLineFixture); const eventWithThirdAndFirstPartyFrames: Event = { exception: { diff --git a/packages/core/test/lib/metadata.test.ts b/packages/core/test/lib/metadata.test.ts index 0036b68657ba..ce85ac8607a0 100644 --- a/packages/core/test/lib/metadata.test.ts +++ b/packages/core/test/lib/metadata.test.ts @@ -1,4 +1,5 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest'; +import type { StackLineParser } from '../../src'; import { addMetadataToStackFrames, getFilenameToMetadataMap, @@ -6,11 +7,20 @@ import { stripMetadataFromStackFrames, } from '../../src/metadata'; import type { Event } from '../../src/types/event'; -import { nodeStackLineParser } from '../../src/utils/node-stack-trace'; import { createStackParser } from '../../src/utils/stacktrace'; import { GLOBAL_OBJ } from '../../src/utils/worldwide'; -const parser = createStackParser(nodeStackLineParser()); +// Minimal Node-style stack-line parser. Sufficient for the `Error().stack` lines +// generated below; the full Node parser now lives in `@sentry-internal/server-utils`. +const nodeStackLineFixture: StackLineParser = [ + 90, + (line: string) => { + const m = line.match(/at (?:async )?(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?/); + return m ? { function: m[1], filename: m[2], lineno: +m[3]!, colno: +m[4]! } : undefined; + }, +]; + +const parser = createStackParser(nodeStackLineFixture); const stack = new Error().stack || ''; diff --git a/packages/core/test/lib/utils/debug-ids.test.ts b/packages/core/test/lib/utils/debug-ids.test.ts index 45ff58c82565..4bd2b200ea41 100644 --- a/packages/core/test/lib/utils/debug-ids.test.ts +++ b/packages/core/test/lib/utils/debug-ids.test.ts @@ -1,9 +1,19 @@ import { beforeEach, describe, expect, it } from 'vitest'; -import { nodeStackLineParser } from '../../../src'; +import type { StackLineParser } from '../../../src'; import { clearDebugIdCache, getDebugImagesForResources, getFilenameToDebugIdMap } from '../../../src/utils/debug-ids'; import { createStackParser } from '../../../src/utils/stacktrace'; -const nodeStackParser = createStackParser(nodeStackLineParser()); +// Minimal Node-style stack-line parser. Sufficient for the fixture lines used +// below; the full Node parser now lives in `@sentry-internal/server-utils`. +const nodeStackLineFixture: StackLineParser = [ + 90, + (line: string) => { + const m = line.match(/at (?:async )?(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?/); + return m ? { function: m[1], filename: m[2]?.replace(/^file:\/\//, ''), lineno: +m[3]!, colno: +m[4]! } : undefined; + }, +]; + +const nodeStackParser = createStackParser(nodeStackLineFixture); describe('getDebugImagesForResources', () => { beforeEach(() => { diff --git a/packages/core/test/lib/utils/eventbuilder.test.ts b/packages/core/test/lib/utils/eventbuilder.test.ts index b882a4562b1c..4fc5fd6216ea 100644 --- a/packages/core/test/lib/utils/eventbuilder.test.ts +++ b/packages/core/test/lib/utils/eventbuilder.test.ts @@ -1,11 +1,21 @@ import { describe, expect, it, test } from 'vitest'; +import type { StackLineParser } from '../../../src'; import type { Client } from '../../../src/client'; import { eventFromMessage, eventFromUnknownInput, exceptionFromError } from '../../../src/utils/eventbuilder'; -import { nodeStackLineParser } from '../../../src/utils/node-stack-trace'; import { addNonEnumerableProperty } from '../../../src/utils/object'; import { createStackParser } from '../../../src/utils/stacktrace'; -const stackParser = createStackParser(nodeStackLineParser()); +// Minimal Node-style stack-line parser. Sufficient for the `Error().stack` lines +// parsed below; the full Node parser now lives in `@sentry-internal/server-utils`. +const nodeStackLineFixture: StackLineParser = [ + 90, + (line: string) => { + const m = line.match(/at (?:async )?(?:(.+?)\s+\()?(.+):(\d+):(\d+)\)?/); + return m ? { function: m[1], filename: m[2], lineno: +m[3]!, colno: +m[4]! } : undefined; + }, +]; + +const stackParser = createStackParser(nodeStackLineFixture); class MyTestClass { prop1 = 'hello'; diff --git a/packages/core/test/lib/utils/flushIfServerless.test.ts b/packages/core/test/lib/utils/flushIfServerless.test.ts index aa0314f183dc..3eaafd6a20ff 100644 --- a/packages/core/test/lib/utils/flushIfServerless.test.ts +++ b/packages/core/test/lib/utils/flushIfServerless.test.ts @@ -1,8 +1,8 @@ +import * as flushModule from '@sentry/core'; +import { GLOBAL_OBJ } from '@sentry/core'; import { afterEach, beforeEach, describe, expect, test, vi } from 'vitest'; -import * as flushModule from '../../../src/exports'; -import { flushIfServerless } from '../../../src/utils/flushIfServerless'; -import * as vercelWaitUntilModule from '../../../src/utils/vercelWaitUntil'; -import { GLOBAL_OBJ } from '../../../src/utils/worldwide'; +import { flushIfServerless } from '../../src/utils/flushIfServerless'; +import * as vercelWaitUntilModule from '../../src/utils/vercelWaitUntil'; describe('flushIfServerless', () => { let originalProcess: typeof process; diff --git a/packages/core/test/lib/utils/node-stack-trace.test.ts b/packages/core/test/lib/utils/node-stack-trace.test.ts new file mode 100644 index 000000000000..b3e097631187 --- /dev/null +++ b/packages/core/test/lib/utils/node-stack-trace.test.ts @@ -0,0 +1,294 @@ +import { beforeEach, describe, expect, it, vi } from 'vitest'; +import { nodeStackLineParser } from '../../src/utils/node-stack-trace'; + +describe('node', () => { + const mockGetModule = vi.fn(); + const parser = nodeStackLineParser(mockGetModule); + const node = parser[1]; + + beforeEach(() => { + mockGetModule.mockReset(); + }); + + it('should return undefined for invalid input', () => { + expect(node('invalid input')).toBeUndefined(); + }); + + it('should extract function, module, filename, lineno, colno, and in_app from valid input', () => { + const input = 'at myFunction (/path/to/file.js:10:5)'; + + const expectedOutput = { + filename: '/path/to/file.js', + module: undefined, + function: 'myFunction', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('extracts module from getModule', () => { + const input = 'at myFunction (/path/to/file.js:10:5)'; + mockGetModule.mockReturnValue('myModule'); + expect(node(input)?.module).toEqual('myModule'); + }); + + it('should extract anonymous function name correctly', () => { + const input = 'at /path/to/file.js:10:5'; + + const expectedOutput = { + filename: '/path/to/file.js', + module: undefined, + function: '?', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('should extract method name and type name correctly', () => { + const input = 'at myObject.myMethod (/path/to/file.js:10:5)'; + + const expectedOutput = { + filename: '/path/to/file.js', + module: undefined, + function: 'myObject.myMethod', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('should handle input with file:// protocol', () => { + const input = 'at myFunction (file:///path/to/file.js:10:5)'; + + const expectedOutput = { + filename: '/path/to/file.js', + module: undefined, + function: 'myFunction', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('should handle input with no line or column number', () => { + const input = 'at myFunction (/path/to/file.js)'; + + const expectedOutput = { + filename: '/path/to/file.js', + module: undefined, + function: 'myFunction', + lineno: undefined, + colno: undefined, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('should handle input with "native" flag', () => { + const input = 'at myFunction (native)'; + + const expectedOutput = { + filename: undefined, + module: undefined, + function: 'myFunction', + lineno: undefined, + colno: undefined, + in_app: false, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('should correctly parse a stack trace line with a function name and file URL', () => { + const line = 'at myFunction (file:///path/to/myFile.js:10:20)'; + const result = node(line); + expect(result).toEqual({ + filename: '/path/to/myFile.js', + function: 'myFunction', + lineno: 10, + colno: 20, + in_app: true, + }); + }); + + it('should correctly parse a stack trace line with a method name and filename', () => { + const line = 'at MyClass.myMethod (/path/to/myFile.js:10:20)'; + const result = node(line); + expect(result).toEqual({ + filename: '/path/to/myFile.js', + module: undefined, + function: 'MyClass.myMethod', + lineno: 10, + colno: 20, + in_app: true, + }); + }); + + it('should correctly parse a stack trace line with an anonymous function', () => { + const line = 'at Object. (/path/to/myFile.js:10:20)'; + const result = node(line); + + expect(result).toEqual({ + filename: '/path/to/myFile.js', + function: 'Object.?', + lineno: 10, + colno: 20, + in_app: true, + }); + }); + + it('should correctly parse a stack trace line with no function or filename', () => { + const line = 'at /path/to/myFile.js:10:20'; + const result = node(line); + expect(result).toEqual({ + filename: '/path/to/myFile.js', + function: '?', + lineno: 10, + colno: 20, + in_app: true, + }); + }); + + it('should correctly parse a stack trace line with a native function', () => { + const line = 'at Object. (native)'; + const result = node(line); + expect(result).toEqual({ + filename: undefined, + function: 'Object.?', + lineno: undefined, + colno: undefined, + in_app: false, + }); + }); + + it('should correctly parse a stack trace line with a module filename', () => { + const line = 'at Object. (/path/to/node_modules/myModule/index.js:10:20)'; + const result = node(line); + + expect(result).toEqual({ + filename: '/path/to/node_modules/myModule/index.js', + function: 'Object.?', + lineno: 10, + colno: 20, + in_app: false, + }); + }); + + it('should correctly parse a stack trace line with a Windows filename', () => { + const line = 'at Object. (C:\\path\\to\\myFile.js:10:20)'; + const result = node(line); + expect(result).toEqual({ + filename: 'C:\\path\\to\\myFile.js', + function: 'Object.?', + lineno: 10, + colno: 20, + in_app: true, + }); + }); + + it('should mark frames with protocols as in_app: true', () => { + const line = 'at Object. (app:///_next/server/pages/[error].js:10:20)'; + const result = node(line); + expect(result?.in_app).toBe(true); + }); + + it('parses frame filename paths with spaces and characters in file name', () => { + const input = 'at myObject.myMethod (/path/to/file with space(1).js:10:5)'; + + const expectedOutput = { + filename: '/path/to/file with space(1).js', + module: undefined, + function: 'myObject.myMethod', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('parses frame filename paths with spaces and characters in file path', () => { + const input = 'at myObject.myMethod (/path with space(1)/to/file.js:10:5)'; + + const expectedOutput = { + filename: '/path with space(1)/to/file.js', + module: undefined, + function: 'myObject.myMethod', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('parses encoded frame filename paths with spaces and characters in file name', () => { + const input = 'at myObject.myMethod (/path/to/file%20with%20space(1).js:10:5)'; + + const expectedOutput = { + filename: '/path/to/file with space(1).js', + module: undefined, + function: 'myObject.myMethod', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('parses encoded frame filename paths with spaces and characters in file path', () => { + const input = 'at myObject.myMethod (/path%20with%20space(1)/to/file.js:10:5)'; + + const expectedOutput = { + filename: '/path with space(1)/to/file.js', + module: undefined, + function: 'myObject.myMethod', + lineno: 10, + colno: 5, + in_app: true, + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('parses function name when filename is a data uri ', () => { + const input = + "at dynamicFn (data:application/javascript,export function dynamicFn() { throw new Error('Error from data-uri module');};:1:38)"; + + const expectedOutput = { + function: 'dynamicFn', + filename: '', + }; + + expect(node(input)).toEqual(expectedOutput); + }); + + it('returns the raw filename when decodeURI throws a URIError', () => { + const malformedFilename = '/path/to/%file%.js'; + const input = `at myFunction (${malformedFilename}:10:5)`; + + const result = node(input); + + expect(result?.filename).toBe('/path/to/%file%.js'); + }); + + it('decodes a valid percent-encoded filename', () => { + const input = 'at myFunction (/path/to/my%20file.js:10:5)'; + + const result = node(input); + + expect(result?.filename).toBe('/path/to/my file.js'); + }); +}); diff --git a/packages/core/test/lib/utils/stacktrace.test.ts b/packages/core/test/lib/utils/stacktrace.test.ts index 2a1700b262a7..2f7c18f3cdf2 100644 --- a/packages/core/test/lib/utils/stacktrace.test.ts +++ b/packages/core/test/lib/utils/stacktrace.test.ts @@ -1,5 +1,4 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { nodeStackLineParser } from '../../../src/utils/node-stack-trace'; +import { describe, expect, it, vi } from 'vitest'; import { createStackParser, stripSentryFramesAndReverse } from '../../../src/utils/stacktrace'; describe('Stacktrace', () => { @@ -183,294 +182,3 @@ describe('Stacktrace', () => { }); }); -describe('node', () => { - const mockGetModule = vi.fn(); - const parser = nodeStackLineParser(mockGetModule); - const node = parser[1]; - - beforeEach(() => { - mockGetModule.mockReset(); - }); - - it('should return undefined for invalid input', () => { - expect(node('invalid input')).toBeUndefined(); - }); - - it('should extract function, module, filename, lineno, colno, and in_app from valid input', () => { - const input = 'at myFunction (/path/to/file.js:10:5)'; - - const expectedOutput = { - filename: '/path/to/file.js', - module: undefined, - function: 'myFunction', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('extracts module from getModule', () => { - const input = 'at myFunction (/path/to/file.js:10:5)'; - mockGetModule.mockReturnValue('myModule'); - expect(node(input)?.module).toEqual('myModule'); - }); - - it('should extract anonymous function name correctly', () => { - const input = 'at /path/to/file.js:10:5'; - - const expectedOutput = { - filename: '/path/to/file.js', - module: undefined, - function: '?', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('should extract method name and type name correctly', () => { - const input = 'at myObject.myMethod (/path/to/file.js:10:5)'; - - const expectedOutput = { - filename: '/path/to/file.js', - module: undefined, - function: 'myObject.myMethod', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('should handle input with file:// protocol', () => { - const input = 'at myFunction (file:///path/to/file.js:10:5)'; - - const expectedOutput = { - filename: '/path/to/file.js', - module: undefined, - function: 'myFunction', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('should handle input with no line or column number', () => { - const input = 'at myFunction (/path/to/file.js)'; - - const expectedOutput = { - filename: '/path/to/file.js', - module: undefined, - function: 'myFunction', - lineno: undefined, - colno: undefined, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('should handle input with "native" flag', () => { - const input = 'at myFunction (native)'; - - const expectedOutput = { - filename: undefined, - module: undefined, - function: 'myFunction', - lineno: undefined, - colno: undefined, - in_app: false, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('should correctly parse a stack trace line with a function name and file URL', () => { - const line = 'at myFunction (file:///path/to/myFile.js:10:20)'; - const result = node(line); - expect(result).toEqual({ - filename: '/path/to/myFile.js', - function: 'myFunction', - lineno: 10, - colno: 20, - in_app: true, - }); - }); - - it('should correctly parse a stack trace line with a method name and filename', () => { - const line = 'at MyClass.myMethod (/path/to/myFile.js:10:20)'; - const result = node(line); - expect(result).toEqual({ - filename: '/path/to/myFile.js', - module: undefined, - function: 'MyClass.myMethod', - lineno: 10, - colno: 20, - in_app: true, - }); - }); - - it('should correctly parse a stack trace line with an anonymous function', () => { - const line = 'at Object. (/path/to/myFile.js:10:20)'; - const result = node(line); - - expect(result).toEqual({ - filename: '/path/to/myFile.js', - function: 'Object.?', - lineno: 10, - colno: 20, - in_app: true, - }); - }); - - it('should correctly parse a stack trace line with no function or filename', () => { - const line = 'at /path/to/myFile.js:10:20'; - const result = node(line); - expect(result).toEqual({ - filename: '/path/to/myFile.js', - function: '?', - lineno: 10, - colno: 20, - in_app: true, - }); - }); - - it('should correctly parse a stack trace line with a native function', () => { - const line = 'at Object. (native)'; - const result = node(line); - expect(result).toEqual({ - filename: undefined, - function: 'Object.?', - lineno: undefined, - colno: undefined, - in_app: false, - }); - }); - - it('should correctly parse a stack trace line with a module filename', () => { - const line = 'at Object. (/path/to/node_modules/myModule/index.js:10:20)'; - const result = node(line); - - expect(result).toEqual({ - filename: '/path/to/node_modules/myModule/index.js', - function: 'Object.?', - lineno: 10, - colno: 20, - in_app: false, - }); - }); - - it('should correctly parse a stack trace line with a Windows filename', () => { - const line = 'at Object. (C:\\path\\to\\myFile.js:10:20)'; - const result = node(line); - expect(result).toEqual({ - filename: 'C:\\path\\to\\myFile.js', - function: 'Object.?', - lineno: 10, - colno: 20, - in_app: true, - }); - }); - - it('should mark frames with protocols as in_app: true', () => { - const line = 'at Object. (app:///_next/server/pages/[error].js:10:20)'; - const result = node(line); - expect(result?.in_app).toBe(true); - }); - - it('parses frame filename paths with spaces and characters in file name', () => { - const input = 'at myObject.myMethod (/path/to/file with space(1).js:10:5)'; - - const expectedOutput = { - filename: '/path/to/file with space(1).js', - module: undefined, - function: 'myObject.myMethod', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('parses frame filename paths with spaces and characters in file path', () => { - const input = 'at myObject.myMethod (/path with space(1)/to/file.js:10:5)'; - - const expectedOutput = { - filename: '/path with space(1)/to/file.js', - module: undefined, - function: 'myObject.myMethod', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('parses encoded frame filename paths with spaces and characters in file name', () => { - const input = 'at myObject.myMethod (/path/to/file%20with%20space(1).js:10:5)'; - - const expectedOutput = { - filename: '/path/to/file with space(1).js', - module: undefined, - function: 'myObject.myMethod', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('parses encoded frame filename paths with spaces and characters in file path', () => { - const input = 'at myObject.myMethod (/path%20with%20space(1)/to/file.js:10:5)'; - - const expectedOutput = { - filename: '/path with space(1)/to/file.js', - module: undefined, - function: 'myObject.myMethod', - lineno: 10, - colno: 5, - in_app: true, - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('parses function name when filename is a data uri ', () => { - const input = - "at dynamicFn (data:application/javascript,export function dynamicFn() { throw new Error('Error from data-uri module');};:1:38)"; - - const expectedOutput = { - function: 'dynamicFn', - filename: '', - }; - - expect(node(input)).toEqual(expectedOutput); - }); - - it('returns the raw filename when decodeURI throws a URIError', () => { - const malformedFilename = '/path/to/%file%.js'; - const input = `at myFunction (${malformedFilename}:10:5)`; - - const result = node(input); - - expect(result?.filename).toBe('/path/to/%file%.js'); - }); - - it('decodes a valid percent-encoded filename', () => { - const input = 'at myFunction (/path/to/my%20file.js:10:5)'; - - const result = node(input); - - expect(result?.filename).toBe('/path/to/my file.js'); - }); -}); diff --git a/packages/core/test/lib/utils/vercelWaitUntil.test.ts b/packages/core/test/lib/utils/vercelWaitUntil.test.ts index 1f6be3b7924f..78e5f574c872 100644 --- a/packages/core/test/lib/utils/vercelWaitUntil.test.ts +++ b/packages/core/test/lib/utils/vercelWaitUntil.test.ts @@ -1,6 +1,6 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { vercelWaitUntil } from '../../../src/utils/vercelWaitUntil'; -import { GLOBAL_OBJ } from '../../../src/utils/worldwide'; +import { GLOBAL_OBJ } from '@sentry/core'; +import { vercelWaitUntil } from '../../src/utils/vercelWaitUntil'; describe('vercelWaitUntil', () => { const VERCEL_REQUEST_CONTEXT_SYMBOL = Symbol.for('@vercel/request-context'); diff --git a/packages/deno/package.json b/packages/deno/package.json index 9e1022104bd2..e23329fa2131 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -25,6 +25,7 @@ ], "dependencies": { "@opentelemetry/api": "^1.9.1", + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0" }, "scripts": { diff --git a/packages/deno/src/client.ts b/packages/deno/src/client.ts index 36886c8d5a5e..3b7018197507 100644 --- a/packages/deno/src/client.ts +++ b/packages/deno/src/client.ts @@ -1,5 +1,6 @@ -import type { ServerRuntimeClientOptions } from '@sentry/core'; -import { _INTERNAL_flushLogsBuffer, SDK_VERSION, ServerRuntimeClient } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; +import { _INTERNAL_flushLogsBuffer, SDK_VERSION } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import type { DenoClientOptions } from './types'; function getHostName(): string | undefined { diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index d06f05f8e4f1..2053027ef535 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -78,7 +78,6 @@ export { rewriteFramesIntegration, supabaseIntegration, instrumentSupabaseClient, - instrumentPostgresJsSql, zodErrorsIntegration, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -91,7 +90,6 @@ export { spanToTraceHeader, spanToBaggageHeader, updateSpanName, - wrapMcpServerWithSentry, featureFlagsIntegration, metrics, withStreamedSpan, @@ -99,6 +97,10 @@ export { consoleLoggingIntegration, spanStreamingIntegration, } from '@sentry/core'; +export { + instrumentPostgresJsSql, + wrapMcpServerWithSentry, +} from '@sentry-internal/server-utils'; export { DenoClient } from './client'; diff --git a/packages/deno/src/integrations/globalhandlers.ts b/packages/deno/src/integrations/globalhandlers.ts index ae66a28068c4..8cefb433a9e8 100644 --- a/packages/deno/src/integrations/globalhandlers.ts +++ b/packages/deno/src/integrations/globalhandlers.ts @@ -1,4 +1,5 @@ -import type { Client, Event, IntegrationFn, Primitive, ServerRuntimeClient, StackParser } from '@sentry/core'; +import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/core'; +import type { ServerRuntimeClient } from '@sentry-internal/server-utils'; import { captureEvent, defineIntegration, eventFromUnknownInput, flush, getClient, isPrimitive } from '@sentry/core'; type GlobalHandlersIntegrationsOptionKeys = 'error' | 'unhandledrejection'; diff --git a/packages/deno/src/integrations/http.ts b/packages/deno/src/integrations/http.ts index d09f0f3ba356..04122312628a 100644 --- a/packages/deno/src/integrations/http.ts +++ b/packages/deno/src/integrations/http.ts @@ -1,16 +1,19 @@ import { subscribe } from 'node:diagnostics_channel'; import { errorMonitor } from 'node:events'; import type { ClientRequest, RequestOptions } from 'node:http'; -import type { HttpIncomingMessage, Integration, IntegrationFn, Span } from '@sentry/core'; +import type { Integration, IntegrationFn, Span } from '@sentry/core'; +import type { HttpIncomingMessage } from '@sentry-internal/server-utils'; import { debug, defineIntegration, +} from '@sentry/core'; +import { getHttpClientSubscriptions, getHttpServerSubscriptions, getRequestOptions, HTTP_ON_CLIENT_REQUEST, HTTP_ON_SERVER_REQUEST, -} from '@sentry/core'; +} from '@sentry-internal/server-utils'; import { setAsyncLocalStorageAsyncContextStrategy } from '../async'; import { DENO_VERSION, diff --git a/packages/deno/src/integrations/normalizepaths.ts b/packages/deno/src/integrations/normalizepaths.ts index 6a2bc6cd95aa..e6ee36495878 100644 --- a/packages/deno/src/integrations/normalizepaths.ts +++ b/packages/deno/src/integrations/normalizepaths.ts @@ -1,5 +1,6 @@ import type { IntegrationFn } from '@sentry/core'; -import { createStackParser, defineIntegration, dirname, nodeStackLineParser } from '@sentry/core'; +import { createStackParser, defineIntegration, dirname } from '@sentry/core'; +import { nodeStackLineParser } from '@sentry-internal/server-utils'; const INTEGRATION_NAME = 'NormalizePaths'; diff --git a/packages/deno/src/sdk.ts b/packages/deno/src/sdk.ts index 62e7dc6a2e70..ccf41b55e7f2 100644 --- a/packages/deno/src/sdk.ts +++ b/packages/deno/src/sdk.ts @@ -1,4 +1,5 @@ -import type { Client, Integration, Options, ServerRuntimeClientOptions, StackParser } from '@sentry/core'; +import type { Client, Integration, Options, StackParser } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; import { createStackParser, dedupeIntegration, @@ -7,11 +8,13 @@ import { inboundFiltersIntegration, initAndBind, linkedErrorsIntegration, - nodeStackLineParser, requestDataIntegration, spanStreamingIntegration, stackParserFromStackParserOptions, } from '@sentry/core'; +import { + nodeStackLineParser, +} from '@sentry-internal/server-utils'; import { DenoClient } from './client'; import { breadcrumbsIntegration } from './integrations/breadcrumbs'; import { denoContextIntegration } from './integrations/context'; diff --git a/packages/deno/test/deno-runtime-metrics.test.ts b/packages/deno/test/deno-runtime-metrics.test.ts index 48435279a954..57a4ba94f2b3 100644 --- a/packages/deno/test/deno-runtime-metrics.test.ts +++ b/packages/deno/test/deno-runtime-metrics.test.ts @@ -1,7 +1,8 @@ // import type { Envelope } from '@sentry/core'; -import { createStackParser, forEachEnvelopeItem, nodeStackLineParser } from '@sentry/core'; +import { createStackParser, forEachEnvelopeItem } from '@sentry/core'; +import { nodeStackLineParser } from '@sentry-internal/server-utils'; import { assertEquals, assertNotEquals, assertStringIncludes } from 'https://deno.land/std@0.212.0/assert/mod.ts'; import { DenoClient, diff --git a/packages/deno/test/mod.test.ts b/packages/deno/test/mod.test.ts index 87eb84b4cb1c..981824c5a4a9 100644 --- a/packages/deno/test/mod.test.ts +++ b/packages/deno/test/mod.test.ts @@ -1,5 +1,6 @@ import type { Envelope, Event, Log } from '@sentry/core'; -import { createStackParser, forEachEnvelopeItem, nodeStackLineParser } from '@sentry/core'; +import { createStackParser, forEachEnvelopeItem } from '@sentry/core'; +import { nodeStackLineParser } from '@sentry-internal/server-utils'; import { assertEquals } from 'https://deno.land/std@0.202.0/assert/assert_equals.ts'; import { assertSnapshot } from 'https://deno.land/std@0.202.0/testing/snapshot.ts'; import { DenoClient, getCurrentScope, getDefaultIntegrations, logger, metrics, Scope } from '../build/esm/index.js'; diff --git a/packages/nextjs/src/common/utils/responseEnd.ts b/packages/nextjs/src/common/utils/responseEnd.ts index 5159897f076e..24269e1ad7f2 100644 --- a/packages/nextjs/src/common/utils/responseEnd.ts +++ b/packages/nextjs/src/common/utils/responseEnd.ts @@ -1,5 +1,6 @@ import type { Span } from '@sentry/core'; -import { debug, fill, flush, GLOBAL_OBJ, setHttpStatus, vercelWaitUntil } from '@sentry/core'; +import { debug, fill, flush, GLOBAL_OBJ, setHttpStatus } from '@sentry/core'; +import { vercelWaitUntil } from '@sentry-internal/server-utils' import type { ServerResponse } from 'http'; import { DEBUG_BUILD } from '../debug-build'; import type { ResponseEndMethod, WrappedResponseEndMethod } from '../types'; diff --git a/packages/nitro/src/runtime/hooks/captureErrorHook.ts b/packages/nitro/src/runtime/hooks/captureErrorHook.ts index fab0c5eff05a..ec25aaa38077 100644 --- a/packages/nitro/src/runtime/hooks/captureErrorHook.ts +++ b/packages/nitro/src/runtime/hooks/captureErrorHook.ts @@ -1,6 +1,5 @@ import { captureException, - flushIfServerless, getActiveSpan, getClient, getCurrentScope, @@ -8,6 +7,7 @@ import { parseUrl, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { HTTPError } from 'h3'; import type { CapturedErrorContext } from 'nitro/types'; diff --git a/packages/nitro/src/runtime/hooks/captureStorageEvents.ts b/packages/nitro/src/runtime/hooks/captureStorageEvents.ts index 054fe6873ce3..554370956da4 100644 --- a/packages/nitro/src/runtime/hooks/captureStorageEvents.ts +++ b/packages/nitro/src/runtime/hooks/captureStorageEvents.ts @@ -1,6 +1,5 @@ import { captureException, - flushIfServerless, GLOBAL_OBJ, SEMANTIC_ATTRIBUTE_CACHE_HIT, SEMANTIC_ATTRIBUTE_CACHE_KEY, @@ -10,6 +9,7 @@ import { SPAN_STATUS_OK, startSpanManual, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { tracingChannel, type TracingChannelContextWithSpan } from '@sentry/opentelemetry/tracing-channel'; import type { TraceContext } from 'unstorage/tracing'; diff --git a/packages/node-core/package.json b/packages/node-core/package.json index 1cfc304cf563..992e6d9a6e53 100644 --- a/packages/node-core/package.json +++ b/packages/node-core/package.json @@ -105,6 +105,7 @@ } }, "dependencies": { + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0", "@sentry/opentelemetry": "10.54.0", "import-in-the-middle": "^3.0.0" diff --git a/packages/node-core/src/common-exports.ts b/packages/node-core/src/common-exports.ts index ddedd5c171eb..b1d123b8b632 100644 --- a/packages/node-core/src/common-exports.ts +++ b/packages/node-core/src/common-exports.ts @@ -109,7 +109,6 @@ export { spanToJSON, spanToTraceHeader, spanToBaggageHeader, - trpcMiddleware, updateSpanName, supabaseIntegration, instrumentSupabaseClient, @@ -117,14 +116,17 @@ export { profiler, consoleLoggingIntegration, createConsolaReporter, - wrapMcpServerWithSentry, featureFlagsIntegration, spanStreamingIntegration, withStreamedSpan, metrics, envToBool, - getRequestUrl, } from '@sentry/core'; +export { + trpcMiddleware, + wrapMcpServerWithSentry, + getRequestUrl, +} from '@sentry-internal/server-utils'; export type { Breadcrumb, diff --git a/packages/node-core/src/integrations/anr/worker.ts b/packages/node-core/src/integrations/anr/worker.ts index 3ae9e009625c..2abce62cdbcf 100644 --- a/packages/node-core/src/integrations/anr/worker.ts +++ b/packages/node-core/src/integrations/anr/worker.ts @@ -3,7 +3,6 @@ import { parentPort, workerData } from 'node:worker_threads'; import type { DebugImage, Event, ScopeData, Session, StackFrame } from '@sentry/core'; import { applyScopeDataToEvent, - callFrameToStackFrame, createEventEnvelope, createSessionEnvelope, generateSpanId, @@ -13,8 +12,11 @@ import { stripSentryFramesAndReverse, updateSession, uuid4, - watchdogTimer, } from '@sentry/core'; +import { + callFrameToStackFrame, + watchdogTimer, +} from '@sentry-internal/server-utils'; import { makeNodeTransport } from '../../transports'; import { createGetModuleFromFilename } from '../../utils/module'; import type { WorkerStartData } from './common'; diff --git a/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts b/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts index 9a53f4ed926e..bb769c39c6ff 100644 --- a/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts +++ b/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts @@ -4,16 +4,19 @@ import { isTracingSuppressed } from '@opentelemetry/core'; import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation'; import type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http'; +import type { + Span, +} from '@sentry/core'; import type { HttpClientRequest, HttpIncomingMessage, HttpInstrumentationOptions, HttpModuleExport, - Span, -} from '@sentry/core'; -import { getHttpClientSubscriptions, patchHttpModuleClient, SDK_VERSION, getRequestOptions } from '@sentry/core'; +} from '@sentry-internal/server-utils'; +import { SDK_VERSION } from '@sentry/core'; +import { getHttpClientSubscriptions, patchHttpModuleClient, getRequestOptions } from '@sentry-internal/server-utils'; import { INSTRUMENTATION_NAME } from './constants'; -import { HTTP_ON_CLIENT_REQUEST } from '@sentry/core'; +import { HTTP_ON_CLIENT_REQUEST } from '@sentry-internal/server-utils'; import { NODE_VERSION } from '../../nodeVersion'; import { errorMonitor } from 'node:events'; import * as http from 'node:http'; diff --git a/packages/node-core/src/integrations/http/httpServerIntegration.ts b/packages/node-core/src/integrations/http/httpServerIntegration.ts index 8a1f9e3de2b5..6220d0e9df2a 100644 --- a/packages/node-core/src/integrations/http/httpServerIntegration.ts +++ b/packages/node-core/src/integrations/http/httpServerIntegration.ts @@ -1,15 +1,18 @@ import { subscribe } from 'node:diagnostics_channel'; import type { RequestOptions } from 'node:http'; import { context, createContextKey, propagation } from '@opentelemetry/api'; -import type { HttpIncomingMessage, HttpServerResponse, Integration, IntegrationFn } from '@sentry/core'; +import type { Integration, IntegrationFn } from '@sentry/core'; +import type { HttpIncomingMessage, HttpServerResponse } from '@sentry-internal/server-utils'; import { addNonEnumerableProperty, debug, getClient, +} from '@sentry/core'; +import { getHttpServerSubscriptions, HTTP_ON_SERVER_REQUEST, recordRequestSession, -} from '@sentry/core'; +} from '@sentry-internal/server-utils'; import type { RequestEventData } from '@sentry/core'; import { DEBUG_BUILD } from '../../debug-build'; diff --git a/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts b/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts index 314f733a7dae..000d5886b4cf 100644 --- a/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts +++ b/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts @@ -13,15 +13,17 @@ import { } from '@opentelemetry/semantic-conventions'; import type { Event, - HttpClientRequest, - HttpIncomingMessage, - HttpServerResponse, Integration, IntegrationFn, Span, SpanAttributes, SpanStatus, } from '@sentry/core'; +import type { + HttpClientRequest, + HttpIncomingMessage, + HttpServerResponse, +} from '@sentry-internal/server-utils'; import { debug, getIsolationScope, diff --git a/packages/node-core/src/integrations/http/index.ts b/packages/node-core/src/integrations/http/index.ts index a59186875c76..f5cc8ac2467b 100644 --- a/packages/node-core/src/integrations/http/index.ts +++ b/packages/node-core/src/integrations/http/index.ts @@ -1,5 +1,5 @@ import type { RequestOptions } from 'node:http'; -import type { HttpIncomingMessage } from '@sentry/core'; +import type { HttpIncomingMessage } from '@sentry-internal/server-utils'; import { defineIntegration } from '@sentry/core'; import { generateInstrumentOnce } from '../../otel/instrument'; import type { NodeClient } from '../../sdk/client'; diff --git a/packages/node-core/src/light/client.ts b/packages/node-core/src/light/client.ts index 074f5231009e..5f91052ccc18 100644 --- a/packages/node-core/src/light/client.ts +++ b/packages/node-core/src/light/client.ts @@ -1,6 +1,7 @@ import * as os from 'node:os'; -import type { ServerRuntimeClientOptions } from '@sentry/core'; -import { _INTERNAL_flushLogsBuffer, applySdkMetadata, debug, ServerRuntimeClient } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; +import { _INTERNAL_flushLogsBuffer, applySdkMetadata, debug } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import { isMainThread, threadId } from 'worker_threads'; import { DEBUG_BUILD } from '../debug-build'; import type { NodeClientOptions } from '../types'; diff --git a/packages/node-core/src/light/integrations/httpIntegration.ts b/packages/node-core/src/light/integrations/httpIntegration.ts index e88ecbdc80ef..6b5f225fb5d4 100644 --- a/packages/node-core/src/light/integrations/httpIntegration.ts +++ b/packages/node-core/src/light/integrations/httpIntegration.ts @@ -1,17 +1,20 @@ import { subscribe } from 'node:diagnostics_channel'; import type { RequestOptions } from 'node:http'; -import type { HttpClientRequest, HttpIncomingMessage, Integration, IntegrationFn } from '@sentry/core'; +import type { Integration, IntegrationFn } from '@sentry/core'; +import type { HttpClientRequest, HttpIncomingMessage } from '@sentry-internal/server-utils'; import { - addOutgoingRequestBreadcrumb, getCurrentScope, + SUPPRESS_TRACING_KEY, +} from '@sentry/core'; +import { + addOutgoingRequestBreadcrumb, getHttpClientSubscriptions, getHttpServerSubscriptions, getRequestOptions, getRequestUrlFromClientRequest, HTTP_ON_CLIENT_REQUEST, HTTP_ON_SERVER_REQUEST, - SUPPRESS_TRACING_KEY, -} from '@sentry/core'; +} from '@sentry-internal/server-utils'; import type { ClientRequest } from 'node:http'; import { errorMonitor } from 'node:events'; import { NODE_VERSION } from '../../nodeVersion'; diff --git a/packages/node-core/src/sdk/api.ts b/packages/node-core/src/sdk/api.ts index 1ccb630f8b32..c92f0337a1de 100644 --- a/packages/node-core/src/sdk/api.ts +++ b/packages/node-core/src/sdk/api.ts @@ -1,7 +1,8 @@ // PUBLIC APIS import type { StackParser } from '@sentry/core'; -import { createStackParser, GLOBAL_OBJ, nodeStackLineParser } from '@sentry/core'; +import { createStackParser, GLOBAL_OBJ } from '@sentry/core'; +import { nodeStackLineParser } from '@sentry-internal/server-utils'; import { createGetModuleFromFilename } from '../utils/module'; /** diff --git a/packages/node-core/src/sdk/client.ts b/packages/node-core/src/sdk/client.ts index 80a233aa3954..d7a65a24ce89 100644 --- a/packages/node-core/src/sdk/client.ts +++ b/packages/node-core/src/sdk/client.ts @@ -3,15 +3,18 @@ import type { Tracer } from '@opentelemetry/api'; import { trace } from '@opentelemetry/api'; import { registerInstrumentations } from '@opentelemetry/instrumentation'; import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; -import type { DynamicSamplingContext, Scope, ServerRuntimeClientOptions, TraceContext } from '@sentry/core'; +import type { DynamicSamplingContext, Scope, TraceContext } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; import { _INTERNAL_clearAiProviderSkips, _INTERNAL_flushLogsBuffer, applySdkMetadata, debug, SDK_VERSION, - ServerRuntimeClient, } from '@sentry/core'; +import { + ServerRuntimeClient, +} from '@sentry-internal/server-utils'; import { type AsyncLocalStorageLookup, getTraceContextForScope } from '@sentry/opentelemetry'; import { isMainThread, threadId } from 'worker_threads'; import { DEBUG_BUILD } from '../debug-build'; diff --git a/packages/node-core/src/types.ts b/packages/node-core/src/types.ts index 174eb039a8c7..982fa02cc0e4 100644 --- a/packages/node-core/src/types.ts +++ b/packages/node-core/src/types.ts @@ -1,7 +1,8 @@ import type { Span as WriteableSpan } from '@opentelemetry/api'; import type { Instrumentation } from '@opentelemetry/instrumentation'; import type { ReadableSpan, SpanProcessor } from '@opentelemetry/sdk-trace-base'; -import type { ClientOptions, Options, SamplingContext, Scope, ServerRuntimeOptions, Span } from '@sentry/core'; +import type { ClientOptions, Options, SamplingContext, Scope, Span } from '@sentry/core'; +import type { ServerRuntimeOptions } from '@sentry-internal/server-utils'; import type { NodeTransportOptions } from './transports'; /** diff --git a/packages/node-core/test/integrations/httpServerIntegration.test.ts b/packages/node-core/test/integrations/httpServerIntegration.test.ts index 555bc9fad16e..da2ae3909be6 100644 --- a/packages/node-core/test/integrations/httpServerIntegration.test.ts +++ b/packages/node-core/test/integrations/httpServerIntegration.test.ts @@ -1,5 +1,6 @@ import type { Client } from '@sentry/core'; -import { createTransport, Scope, ServerRuntimeClient, withScope } from '@sentry/core'; +import { createTransport, Scope, withScope } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import { EventEmitter } from 'stream'; import { describe, expect, it, vi } from 'vitest'; import { recordRequestSession } from '../../src/integrations/http/httpServerIntegration'; diff --git a/packages/node-native/package.json b/packages/node-native/package.json index 01b692907122..ff0d4df832b6 100644 --- a/packages/node-native/package.json +++ b/packages/node-native/package.json @@ -63,6 +63,7 @@ }, "dependencies": { "@sentry-internal/node-native-stacktrace": "^0.5.0", + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0", "@sentry/node": "10.54.0" }, diff --git a/packages/node-native/src/event-loop-block-watchdog.ts b/packages/node-native/src/event-loop-block-watchdog.ts index cac20909d6a5..234aafa4b5d6 100644 --- a/packages/node-native/src/event-loop-block-watchdog.ts +++ b/packages/node-native/src/event-loop-block-watchdog.ts @@ -4,7 +4,6 @@ import { applyScopeDataToEvent, createEventEnvelope, createSessionEnvelope, - filenameIsInApp, generateSpanId, getEnvelopeEndpointWithUrlEncodedAuth, makeSession, @@ -15,6 +14,9 @@ import { updateSession, uuid4, } from '@sentry/core'; +import { + filenameIsInApp, +} from '@sentry-internal/server-utils'; import { makeNodeTransport } from '@sentry/node'; import { captureStackTrace, getThreadsLastSeen } from '@sentry-internal/node-native-stacktrace'; import type { ThreadState, WorkerStartData } from './common'; diff --git a/packages/node/package.json b/packages/node/package.json index bfa8272d6821..7f4354504205 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -70,6 +70,7 @@ "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/sdk-trace-base": "^2.6.1", "@opentelemetry/semantic-conventions": "^1.40.0", + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0", "@sentry/node-core": "10.54.0", "@sentry/opentelemetry": "10.54.0", diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 3bd5e1edba1c..6083177aebe1 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -126,7 +126,6 @@ export { spanToJSON, spanToTraceHeader, spanToBaggageHeader, - trpcMiddleware, updateSpanName, supabaseIntegration, instrumentSupabaseClient, @@ -137,7 +136,6 @@ export { profiler, consoleLoggingIntegration, createConsolaReporter, - wrapMcpServerWithSentry, featureFlagsIntegration, spanStreamingIntegration, createLangChainCallbackHandler, @@ -145,6 +143,10 @@ export { instrumentLangGraph, instrumentStateGraphCompile, } from '@sentry/core'; +export { + trpcMiddleware, + wrapMcpServerWithSentry, +} from '@sentry-internal/server-utils'; export type { Breadcrumb, diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 7786747dc9ee..25f1e7397f8e 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,12 +1,15 @@ import type { RequestOptions } from 'node:http'; -import type { HttpClientRequest, HttpIncomingMessage, HttpServerResponse, Span } from '@sentry/core'; +import type { Span } from '@sentry/core'; +import type { HttpClientRequest, HttpIncomingMessage, HttpServerResponse } from '@sentry-internal/server-utils'; import { defineIntegration, hasSpansEnabled, SEMANTIC_ATTRIBUTE_URL_FULL, stripDataUrlContent, - getRequestUrlFromClientRequest, } from '@sentry/core'; +import { + getRequestUrlFromClientRequest, +} from '@sentry-internal/server-utils'; import type { NodeClient, SentryHttpInstrumentationOptions, diff --git a/packages/node/src/integrations/tracing/express.ts b/packages/node/src/integrations/tracing/express.ts index c0f7cbc2414f..39ee1da2f0e1 100644 --- a/packages/node/src/integrations/tracing/express.ts +++ b/packages/node/src/integrations/tracing/express.ts @@ -6,16 +6,18 @@ import { getRPCMetadata, RPCType } from '@opentelemetry/core'; import { ensureIsWrapped, generateInstrumentOnce } from '@sentry/node-core'; import { - type ExpressIntegrationOptions, type IntegrationFn, debug, - patchExpressModule, SDK_VERSION, defineIntegration, +} from '@sentry/core'; +import { + type ExpressIntegrationOptions, + patchExpressModule, setupExpressErrorHandler as coreSetupExpressErrorHandler, type ExpressHandlerOptions, -} from '@sentry/core'; -export { expressErrorHandler } from '@sentry/core'; +} from '@sentry-internal/server-utils'; +export { expressErrorHandler } from '@sentry-internal/server-utils'; import { DEBUG_BUILD } from '../../debug-build'; const INTEGRATION_NAME = 'Express'; diff --git a/packages/node/src/integrations/tracing/postgresjs.ts b/packages/node/src/integrations/tracing/postgresjs.ts index 86f7952712d2..848e2b1bf77b 100644 --- a/packages/node/src/integrations/tracing/postgresjs.ts +++ b/packages/node/src/integrations/tracing/postgresjs.ts @@ -19,12 +19,14 @@ import type { IntegrationFn, Span } from '@sentry/core'; import { debug, defineIntegration, - instrumentPostgresJsSql, replaceExports, SDK_VERSION, SPAN_STATUS_ERROR, startSpanManual, } from '@sentry/core'; +import { + instrumentPostgresJsSql, +} from '@sentry-internal/server-utils'; import { addOriginToSpan, generateInstrumentOnce } from '@sentry/node-core'; import { DEBUG_BUILD } from '../../debug-build'; diff --git a/packages/nuxt/src/runtime/hooks/captureErrorHook.ts b/packages/nuxt/src/runtime/hooks/captureErrorHook.ts index b8e53f0ca0c3..49788958e9a4 100644 --- a/packages/nuxt/src/runtime/hooks/captureErrorHook.ts +++ b/packages/nuxt/src/runtime/hooks/captureErrorHook.ts @@ -1,4 +1,5 @@ -import { captureException, flushIfServerless, getClient, getCurrentScope } from '@sentry/core'; +import { captureException, getClient, getCurrentScope } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; // eslint-disable-next-line import/no-extraneous-dependencies import { H3Error } from 'h3'; import type { CapturedErrorContext } from 'nitropack/types'; diff --git a/packages/nuxt/src/runtime/hooks/wrapMiddlewareHandler.ts b/packages/nuxt/src/runtime/hooks/wrapMiddlewareHandler.ts index c0e79c902b93..b705dd9ddb75 100644 --- a/packages/nuxt/src/runtime/hooks/wrapMiddlewareHandler.ts +++ b/packages/nuxt/src/runtime/hooks/wrapMiddlewareHandler.ts @@ -1,7 +1,6 @@ import { captureException, debug, - flushIfServerless, getClient, httpHeadersToSpanAttributes, SEMANTIC_ATTRIBUTE_SENTRY_OP, @@ -12,6 +11,7 @@ import { type SpanAttributes, startSpan, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { _ResponseMiddleware as ResponseMiddleware, EventHandler, diff --git a/packages/nuxt/src/runtime/utils/instrumentDatabase.ts b/packages/nuxt/src/runtime/utils/instrumentDatabase.ts index 9f7d320fe390..3844ac50a590 100644 --- a/packages/nuxt/src/runtime/utils/instrumentDatabase.ts +++ b/packages/nuxt/src/runtime/utils/instrumentDatabase.ts @@ -2,7 +2,6 @@ import { addBreadcrumb, captureException, debug, - flushIfServerless, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, type Span, @@ -10,6 +9,7 @@ import { startSpan, type StartSpanOptions, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { Database, PreparedStatement } from 'db0'; import { type DatabaseConnectionConfig, type DatabaseSpanData, getDatabaseSpanData } from './database-span-data'; diff --git a/packages/nuxt/src/runtime/utils/instrumentStorage.ts b/packages/nuxt/src/runtime/utils/instrumentStorage.ts index e51666aba79b..91ffa785648f 100644 --- a/packages/nuxt/src/runtime/utils/instrumentStorage.ts +++ b/packages/nuxt/src/runtime/utils/instrumentStorage.ts @@ -1,7 +1,6 @@ import { captureException, debug, - flushIfServerless, SEMANTIC_ATTRIBUTE_CACHE_HIT, SEMANTIC_ATTRIBUTE_CACHE_KEY, SEMANTIC_ATTRIBUTE_SENTRY_OP, @@ -12,6 +11,7 @@ import { startSpan, type StartSpanOptions, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { Driver, Storage } from 'unstorage'; /** diff --git a/packages/nuxt/src/runtime/utils/patchEventHandler.ts b/packages/nuxt/src/runtime/utils/patchEventHandler.ts index 41625012c10c..3a1591c377fd 100644 --- a/packages/nuxt/src/runtime/utils/patchEventHandler.ts +++ b/packages/nuxt/src/runtime/utils/patchEventHandler.ts @@ -1,10 +1,10 @@ import { debug, - flushIfServerless, getDefaultIsolationScope, getIsolationScope, withIsolationScope, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; /** * Patches the H3 event handler of Nitro. diff --git a/packages/nuxt/src/server/sdk.ts b/packages/nuxt/src/server/sdk.ts index bf262dc40a24..35e1b887a56e 100644 --- a/packages/nuxt/src/server/sdk.ts +++ b/packages/nuxt/src/server/sdk.ts @@ -7,8 +7,8 @@ import { DEV_ENVIRONMENT, flush, getGlobalScope, - vercelWaitUntil, } from '@sentry/core'; +import { vercelWaitUntil } from '@sentry-internal/server-utils' import { getDefaultIntegrations as getDefaultNodeIntegrations, httpIntegration, diff --git a/packages/react-router/package.json b/packages/react-router/package.json index aef080b0fac7..c6b556607063 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -49,6 +49,7 @@ "@opentelemetry/core": "^2.6.1", "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/semantic-conventions": "^1.40.0", + "@sentry-internal/server-utils": "10.54.0", "@sentry/browser": "10.54.0", "@sentry/cli": "^2.58.6", "@sentry/core": "10.54.0", diff --git a/packages/react-router/src/server/createSentryHandleError.ts b/packages/react-router/src/server/createSentryHandleError.ts index c8d1dbc6118e..0748ae882c87 100644 --- a/packages/react-router/src/server/createSentryHandleError.ts +++ b/packages/react-router/src/server/createSentryHandleError.ts @@ -1,4 +1,5 @@ -import { captureException, flushIfServerless } from '@sentry/core'; +import { captureException } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { HandleErrorFunction } from 'react-router'; export type SentryHandleErrorOptions = { diff --git a/packages/react-router/src/server/createServerInstrumentation.ts b/packages/react-router/src/server/createServerInstrumentation.ts index 7eb7cc6c163e..609fed5098f1 100644 --- a/packages/react-router/src/server/createServerInstrumentation.ts +++ b/packages/react-router/src/server/createServerInstrumentation.ts @@ -3,7 +3,6 @@ import { getRPCMetadata, RPCType } from '@opentelemetry/core'; import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'; import { debug, - flushIfServerless, getActiveSpan, getCurrentScope, getRootSpan, @@ -14,6 +13,7 @@ import { startSpan, updateSpanName, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { DEBUG_BUILD } from '../common/debug-build'; import type { InstrumentableRequestHandler, InstrumentableRoute, ServerInstrumentation } from '../common/types'; import { captureInstrumentationError, getPathFromRequest, getPattern, normalizeRoutePath } from '../common/utils'; diff --git a/packages/react-router/src/server/wrapSentryHandleRequest.ts b/packages/react-router/src/server/wrapSentryHandleRequest.ts index 9bf634a68505..63ba6453ff44 100644 --- a/packages/react-router/src/server/wrapSentryHandleRequest.ts +++ b/packages/react-router/src/server/wrapSentryHandleRequest.ts @@ -2,7 +2,6 @@ import { context } from '@opentelemetry/api'; import { getRPCMetadata, RPCType } from '@opentelemetry/core'; import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'; import { - flushIfServerless, getActiveSpan, getCurrentScope, getRootSpan, @@ -10,6 +9,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, updateSpanName, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { AppLoadContext, EntryContext, RouterContextProvider } from 'react-router'; import { isInstrumentationApiUsed } from './serverGlobals'; diff --git a/packages/react-router/src/server/wrapServerAction.ts b/packages/react-router/src/server/wrapServerAction.ts index 356237008650..cf31ae393b2d 100644 --- a/packages/react-router/src/server/wrapServerAction.ts +++ b/packages/react-router/src/server/wrapServerAction.ts @@ -2,7 +2,6 @@ import { SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions'; import type { SpanAttributes } from '@sentry/core'; import { debug, - flushIfServerless, getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, @@ -12,6 +11,7 @@ import { startSpan, updateSpanName, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { ActionFunctionArgs } from 'react-router'; import { DEBUG_BUILD } from '../common/debug-build'; import { isInstrumentationApiUsed } from './serverGlobals'; diff --git a/packages/react-router/src/server/wrapServerLoader.ts b/packages/react-router/src/server/wrapServerLoader.ts index a3146d0de24a..d49a13667dc0 100644 --- a/packages/react-router/src/server/wrapServerLoader.ts +++ b/packages/react-router/src/server/wrapServerLoader.ts @@ -2,7 +2,6 @@ import { SEMATTRS_HTTP_TARGET } from '@opentelemetry/semantic-conventions'; import type { SpanAttributes } from '@sentry/core'; import { debug, - flushIfServerless, getActiveSpan, getRootSpan, SEMANTIC_ATTRIBUTE_SENTRY_OP, @@ -12,6 +11,7 @@ import { startSpan, updateSpanName, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { LoaderFunctionArgs } from 'react-router'; import { DEBUG_BUILD } from '../common/debug-build'; import { isInstrumentationApiUsed } from './serverGlobals'; diff --git a/packages/react-router/test/server/wrapSentryHandleRequest.test.ts b/packages/react-router/test/server/wrapSentryHandleRequest.test.ts index 71875d1aa887..16e45e3dde3c 100644 --- a/packages/react-router/test/server/wrapSentryHandleRequest.test.ts +++ b/packages/react-router/test/server/wrapSentryHandleRequest.test.ts @@ -2,13 +2,15 @@ import { PassThrough } from 'node:stream'; import { RPCType } from '@opentelemetry/core'; import { ATTR_HTTP_ROUTE } from '@opentelemetry/semantic-conventions'; import { - flushIfServerless, getActiveSpan, getRootSpan, getTraceMetaTags, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, } from '@sentry/core'; +import { + flushIfServerless, +} from '@sentry-internal/server-utils'; import { beforeEach, describe, expect, test, vi } from 'vitest'; import { getMetaTagTransformer } from '../../src/server/getMetaTagTransformer'; import { wrapSentryHandleRequest } from '../../src/server/wrapSentryHandleRequest'; diff --git a/packages/remix/package.json b/packages/remix/package.json index 82ec7b6c6c0f..0162e1f169d6 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -68,6 +68,7 @@ "@opentelemetry/instrumentation": "^0.214.0", "@opentelemetry/semantic-conventions": "^1.40.0", "@remix-run/router": "^1.23.2", + "@sentry-internal/server-utils": "10.54.0", "@sentry/cli": "^2.58.6", "@sentry/core": "10.54.0", "@sentry/node": "10.54.0", diff --git a/packages/remix/src/cloudflare/index.ts b/packages/remix/src/cloudflare/index.ts index 97f2609bf10d..8d478f30f8ad 100644 --- a/packages/remix/src/cloudflare/index.ts +++ b/packages/remix/src/cloudflare/index.ts @@ -109,7 +109,6 @@ export { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, - trpcMiddleware, spanToJSON, spanToTraceHeader, spanToBaggageHeader, @@ -117,3 +116,6 @@ export { withStreamedSpan, featureFlagsIntegration, } from '@sentry/core'; +export { + trpcMiddleware, +} from '@sentry-internal/server-utils'; diff --git a/packages/server-utils/src/debug-build.ts b/packages/server-utils/src/debug-build.ts new file mode 100644 index 000000000000..60aa50940582 --- /dev/null +++ b/packages/server-utils/src/debug-build.ts @@ -0,0 +1,8 @@ +declare const __DEBUG_BUILD__: boolean; + +/** + * This serves as a build time flag that will be true by default, but false in non-debug builds or if users replace `__SENTRY_DEBUG__` in their generated code. + * + * ATTENTION: This constant must never cross package boundaries (i.e. be exported) to guarantee that it can be used for tree shaking. + */ +export const DEBUG_BUILD = __DEBUG_BUILD__; diff --git a/packages/server-utils/src/index.ts b/packages/server-utils/src/index.ts index 6dfa1d221b70..cad3d10f4490 100644 --- a/packages/server-utils/src/index.ts +++ b/packages/server-utils/src/index.ts @@ -1,4 +1,37 @@ -// Public surface intentionally left empty in this initial scaffold. -// Symbols will land here as code is migrated out of `@sentry/core` per the -// server-utils migration plan. -export {}; +export { wrapMcpServerWithSentry } from './integrations/mcp-server'; +export { instrumentPostgresJsSql } from './integrations/postgresjs'; +export { expressErrorHandler, patchExpressModule, setupExpressErrorHandler } from './integrations/express/index'; +export type { + ExpressErrorMiddleware, + ExpressHandlerOptions, + ExpressIntegrationOptions, + ExpressMiddleware, +} from './integrations/express/types'; +export { addOutgoingRequestBreadcrumb } from './integrations/http/add-outgoing-request-breadcrumb'; +export { patchHttpModuleClient } from './integrations/http/client-patch'; +export { getHttpClientSubscriptions } from './integrations/http/client-subscriptions'; +export { HTTP_ON_CLIENT_REQUEST, HTTP_ON_SERVER_REQUEST } from './integrations/http/constants'; +export { + getRequestOptions, + getRequestUrl, + getRequestUrlFromClientRequest, + getRequestUrlObject, +} from './integrations/http/get-request-url'; +export { recordRequestSession } from './integrations/http/record-request-session'; +export { getHttpServerSubscriptions, isStaticAssetRequest } from './integrations/http/server-subscription'; +export type { + HttpClientRequest, + HttpIncomingMessage, + HttpInstrumentationOptions, + HttpModuleExport, + HttpServerResponse, +} from './integrations/http/types'; +export { ServerRuntimeClient } from './server-runtime-client'; +export type { ServerRuntimeClientOptions } from './server-runtime-client'; +export { trpcMiddleware } from './trpc'; +export type { ServerRuntimeOptions } from './types/server-runtime-options'; +export { callFrameToStackFrame, watchdogTimer } from './utils/anr'; +export { flushIfServerless } from './utils/flushIfServerless'; +export { filenameIsInApp, node, nodeStackLineParser } from './utils/node-stack-trace'; +export type { GetModuleFn } from './utils/node-stack-trace'; +export { vercelWaitUntil } from './utils/vercelWaitUntil'; diff --git a/packages/core/src/integrations/express/index.ts b/packages/server-utils/src/integrations/express/index.ts similarity index 88% rename from packages/core/src/integrations/express/index.ts rename to packages/server-utils/src/integrations/express/index.ts index df616e7b7f32..419d7592ae27 100644 --- a/packages/core/src/integrations/express/index.ts +++ b/packages/server-utils/src/integrations/express/index.ts @@ -27,8 +27,8 @@ * limitations under the License. */ -import { debug } from '../../utils/debug-logger'; -import { captureException } from '../../exports'; +import { debug } from '@sentry/core'; +import { captureException } from '@sentry/core'; import { DEBUG_BUILD } from '../../debug-build'; import type { ExpressApplication, @@ -51,10 +51,43 @@ import { isExpressWithoutRouterPrototype, isExpressWithRouterPrototype, } from './utils'; -import { wrapMethod } from '../../utils/object'; +import { getOriginalFunction, markFunctionWrapped, type WrappedFunction } from '@sentry/core'; import { patchLayer } from './patch-layer'; import { setSDKProcessingMetadata } from './set-sdk-processing-metadata'; -import { getDefaultExport } from '../../utils/get-default-export'; + +// Vendored from `@sentry/core`'s private `utils/get-default-export.ts`. +function getDefaultExport(moduleExport: T | { default: T }): T { + return ( + (!!moduleExport && + typeof moduleExport === 'object' && + 'default' in moduleExport && + (moduleExport as { default: T }).default) || + (moduleExport as T) + ); +} + +// Vendored from `@sentry/core`'s private `utils/object.ts`. +function wrapMethod( + obj: O, + field: T, + wrapped: WrappedFunction, + enumerable: boolean = true, +): void { + const original = obj[field]; + if (typeof original !== 'function') { + throw new Error(`Cannot wrap method: ${field} is not a function`); + } + if (getOriginalFunction(original)) { + throw new Error(`Attempting to wrap method ${field} multiple times`); + } + markFunctionWrapped(wrapped, original); + Object.defineProperty(obj, field, { + writable: true, + configurable: true, + enumerable, + value: wrapped, + }); +} function isLegacyOptions( options: ExpressModuleExport | (ExpressIntegrationOptions & { express: ExpressModuleExport }), diff --git a/packages/core/src/integrations/express/patch-layer.ts b/packages/server-utils/src/integrations/express/patch-layer.ts similarity index 95% rename from packages/core/src/integrations/express/patch-layer.ts rename to packages/server-utils/src/integrations/express/patch-layer.ts index 6a026afa67f8..622137220f3c 100644 --- a/packages/core/src/integrations/express/patch-layer.ts +++ b/packages/server-utils/src/integrations/express/patch-layer.ts @@ -28,11 +28,11 @@ */ import { DEBUG_BUILD } from '../../debug-build'; -import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../../semanticAttributes'; -import { SPAN_STATUS_ERROR, startSpanManual, withActiveSpan } from '../../tracing'; -import { debug } from '../../utils/debug-logger'; -import type { SpanAttributes } from '../../types/span'; -import { getActiveSpan } from '../../utils/spanUtils'; +import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '@sentry/core'; +import { SPAN_STATUS_ERROR, startSpanManual, withActiveSpan } from '@sentry/core'; +import { debug } from '@sentry/core'; +import type { SpanAttributes } from '@sentry/core'; +import { getActiveSpan } from '@sentry/core'; import { getStoredLayers, storeLayer } from './request-layer-store'; import { type ExpressRequest, @@ -51,9 +51,9 @@ import { getLayerMetadata, isLayerIgnored, } from './utils'; -import { getIsolationScope } from '../../currentScopes'; -import { getDefaultIsolationScope } from '../../defaultScopes'; -import { getOriginalFunction, markFunctionWrapped } from '../../utils/object'; +import { getIsolationScope } from '@sentry/core'; +import { getDefaultIsolationScope } from '@sentry/core'; +import { getOriginalFunction, markFunctionWrapped } from '@sentry/core'; import { setSDKProcessingMetadata } from './set-sdk-processing-metadata'; export type ExpressPatchLayerOptions = Pick< diff --git a/packages/core/src/integrations/express/request-layer-store.ts b/packages/server-utils/src/integrations/express/request-layer-store.ts similarity index 100% rename from packages/core/src/integrations/express/request-layer-store.ts rename to packages/server-utils/src/integrations/express/request-layer-store.ts diff --git a/packages/core/src/integrations/express/set-sdk-processing-metadata.ts b/packages/server-utils/src/integrations/express/set-sdk-processing-metadata.ts similarity index 93% rename from packages/core/src/integrations/express/set-sdk-processing-metadata.ts rename to packages/server-utils/src/integrations/express/set-sdk-processing-metadata.ts index 0b694a40a360..dd50ad1e6b16 100644 --- a/packages/core/src/integrations/express/set-sdk-processing-metadata.ts +++ b/packages/server-utils/src/integrations/express/set-sdk-processing-metadata.ts @@ -33,8 +33,8 @@ */ import type { ExpressRequest } from './types'; -import { getIsolationScope } from '../../currentScopes'; -import { httpRequestToRequestData } from '../../utils/request'; +import { getIsolationScope } from '@sentry/core'; +import { httpRequestToRequestData } from '@sentry/core'; // TODO: consider moving this into a core util, eg // setSDKProcessingMetadataFromRequest(..), if other integrations need it. diff --git a/packages/core/src/integrations/express/types.ts b/packages/server-utils/src/integrations/express/types.ts similarity index 97% rename from packages/core/src/integrations/express/types.ts rename to packages/server-utils/src/integrations/express/types.ts index dc5fe252a820..29ea889940df 100644 --- a/packages/core/src/integrations/express/types.ts +++ b/packages/server-utils/src/integrations/express/types.ts @@ -27,8 +27,8 @@ * limitations under the License. */ -import type { RequestEventData } from '../../types/request'; -import type { SpanAttributes } from '../../types/span'; +import type { RequestEventData } from '@sentry/core'; +import type { SpanAttributes } from '@sentry/core'; export const ATTR_EXPRESS_NAME = 'express.name'; export const ATTR_HTTP_ROUTE = 'http.route'; diff --git a/packages/core/src/integrations/express/utils.ts b/packages/server-utils/src/integrations/express/utils.ts similarity index 98% rename from packages/core/src/integrations/express/utils.ts rename to packages/server-utils/src/integrations/express/utils.ts index 55a3325ad172..989bfa984872 100644 --- a/packages/core/src/integrations/express/utils.ts +++ b/packages/server-utils/src/integrations/express/utils.ts @@ -27,7 +27,7 @@ * limitations under the License. */ -import type { SpanAttributes } from '../../types/span'; +import type { SpanAttributes } from '@sentry/core'; import { getStoredLayers } from './request-layer-store'; import type { ExpressIntegrationOptions, @@ -47,7 +47,7 @@ import { ExpressLayerType_REQUEST_HANDLER, ExpressLayerType_ROUTER, } from './types'; -import { stringMatchesSomePattern } from '../../utils/string'; +import { stringMatchesSomePattern } from '@sentry/core'; /** * Converts a user-provided error value into an error and error message pair diff --git a/packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts b/packages/server-utils/src/integrations/http/add-outgoing-request-breadcrumb.ts similarity index 82% rename from packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts rename to packages/server-utils/src/integrations/http/add-outgoing-request-breadcrumb.ts index 251dbfc540a6..9624e3460931 100644 --- a/packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts +++ b/packages/server-utils/src/integrations/http/add-outgoing-request-breadcrumb.ts @@ -1,6 +1,6 @@ -import { addBreadcrumb } from '../../breadcrumbs'; -import { getBreadcrumbLogLevelFromHttpStatusCode } from '../../utils/breadcrumb-log-level'; -import { getSanitizedUrlString, parseUrl } from '../../utils/url'; +import { addBreadcrumb } from '@sentry/core'; +import { getBreadcrumbLogLevelFromHttpStatusCode } from '@sentry/core'; +import { getSanitizedUrlString, parseUrl } from '@sentry/core'; import { getRequestUrlFromClientRequest } from './get-request-url'; import type { HttpClientRequest, HttpIncomingMessage } from './types'; diff --git a/packages/core/src/integrations/http/client-patch.ts b/packages/server-utils/src/integrations/http/client-patch.ts similarity index 77% rename from packages/core/src/integrations/http/client-patch.ts rename to packages/server-utils/src/integrations/http/client-patch.ts index fba60fd9c198..f081b7069524 100644 --- a/packages/core/src/integrations/http/client-patch.ts +++ b/packages/server-utils/src/integrations/http/client-patch.ts @@ -31,11 +31,44 @@ * limitations under the License. */ -import { getDefaultExport } from '../../utils/get-default-export'; -import { HTTP_ON_CLIENT_REQUEST } from './constants'; -import type { HttpExport, HttpModuleExport, HttpInstrumentationOptions, HttpClientRequest } from './types'; -import { getOriginalFunction, wrapMethod } from '../../utils/object'; +import { getOriginalFunction, markFunctionWrapped, type WrappedFunction } from '@sentry/core'; import { getHttpClientSubscriptions } from './client-subscriptions'; +import { HTTP_ON_CLIENT_REQUEST } from './constants'; +import type { HttpClientRequest, HttpExport, HttpInstrumentationOptions, HttpModuleExport } from './types'; + +// Vendored from `@sentry/core`'s private `utils/get-default-export.ts`. +function getDefaultExport(moduleExport: T | { default: T }): T { + return ( + (!!moduleExport && + typeof moduleExport === 'object' && + 'default' in moduleExport && + (moduleExport as { default: T }).default) || + (moduleExport as T) + ); +} + +// Vendored from `@sentry/core`'s private `utils/object.ts`. +function wrapMethod( + obj: O, + field: T, + wrapped: WrappedFunction, + enumerable: boolean = true, +): void { + const original = obj[field]; + if (typeof original !== 'function') { + throw new Error(`Cannot wrap method: ${field} is not a function`); + } + if (getOriginalFunction(original)) { + throw new Error(`Attempting to wrap method ${field} multiple times`); + } + markFunctionWrapped(wrapped, original); + Object.defineProperty(obj, field, { + writable: true, + configurable: true, + enumerable, + value: wrapped, + }); +} function patchHttpRequest(httpModule: HttpExport, options: HttpInstrumentationOptions): void { // avoid double-wrap diff --git a/packages/core/src/integrations/http/client-subscriptions.ts b/packages/server-utils/src/integrations/http/client-subscriptions.ts similarity index 95% rename from packages/core/src/integrations/http/client-subscriptions.ts rename to packages/server-utils/src/integrations/http/client-subscriptions.ts index 71d78873dbb2..80b2e361f4c3 100644 --- a/packages/core/src/integrations/http/client-subscriptions.ts +++ b/packages/server-utils/src/integrations/http/client-subscriptions.ts @@ -13,7 +13,7 @@ * calling the handlers with the relevant data at the appropriate time. */ -import type { SpanStatus } from '../../types/spanStatus'; +import type { SpanStatus } from '@sentry/core'; import { addOutgoingRequestBreadcrumb } from './add-outgoing-request-breadcrumb'; import { getSpanStatusFromHttpCode, @@ -22,9 +22,9 @@ import { startInactiveSpan, SUPPRESS_TRACING_KEY, withActiveSpan, -} from '../../tracing'; -import { debug } from '../../utils/debug-logger'; -import { LRUMap } from '../../utils/lru'; +} from '@sentry/core'; +import { debug } from '@sentry/core'; +import { LRUMap } from '@sentry/core'; import { getOutgoingRequestSpanData, setIncomingResponseSpanData } from './get-outgoing-span-data'; import { getRequestUrlFromClientRequest } from './get-request-url'; import { injectTracePropagationHeaders } from './inject-trace-propagation-headers'; @@ -32,8 +32,8 @@ import type { HttpInstrumentationOptions, HttpClientRequest, HttpIncomingMessage import { DEBUG_BUILD } from '../../debug-build'; import { LOG_PREFIX, HTTP_ON_CLIENT_REQUEST } from './constants'; import type { ClientSubscriptionName } from './constants'; -import { getClient, getCurrentScope } from '../../currentScopes'; -import { hasSpansEnabled } from '../../utils/hasSpansEnabled'; +import { getClient, getCurrentScope } from '@sentry/core'; +import { hasSpansEnabled } from '@sentry/core'; import { doubleWrapWarning } from './double-wrap-warning'; type ChannelListener = (message: unknown, name: string | symbol) => void; diff --git a/packages/core/src/integrations/http/constants.ts b/packages/server-utils/src/integrations/http/constants.ts similarity index 100% rename from packages/core/src/integrations/http/constants.ts rename to packages/server-utils/src/integrations/http/constants.ts diff --git a/packages/core/src/integrations/http/double-wrap-warning.ts b/packages/server-utils/src/integrations/http/double-wrap-warning.ts similarity index 94% rename from packages/core/src/integrations/http/double-wrap-warning.ts rename to packages/server-utils/src/integrations/http/double-wrap-warning.ts index bb0b00c7659c..7b54ab56b5e8 100644 --- a/packages/core/src/integrations/http/double-wrap-warning.ts +++ b/packages/server-utils/src/integrations/http/double-wrap-warning.ts @@ -1,5 +1,5 @@ import { DEBUG_BUILD } from '../../debug-build'; -import { debug } from '../../utils/debug-logger'; +import { debug } from '@sentry/core'; import type { HttpModuleExport } from './types'; const isOtelWrapped = (fn: Function & { __unwrap?: Function }): fn is Function & { __unwrap: Function } => diff --git a/packages/core/src/integrations/http/get-outgoing-span-data.ts b/packages/server-utils/src/integrations/http/get-outgoing-span-data.ts similarity index 92% rename from packages/core/src/integrations/http/get-outgoing-span-data.ts rename to packages/server-utils/src/integrations/http/get-outgoing-span-data.ts index 8092bec8c5bf..390e29d8c927 100644 --- a/packages/core/src/integrations/http/get-outgoing-span-data.ts +++ b/packages/server-utils/src/integrations/http/get-outgoing-span-data.ts @@ -1,9 +1,9 @@ -import type { Span, SpanAttributes } from '../../types/span'; -import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../../semanticAttributes'; -import { getHttpSpanDetailsFromUrlObject, parseStringToURLObject } from '../../utils/url'; +import type { Span, SpanAttributes } from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '@sentry/core'; +import { getHttpSpanDetailsFromUrlObject, parseStringToURLObject } from '@sentry/core'; import type { HttpClientRequest, HttpIncomingMessage } from './types'; import { getRequestUrlFromClientRequest } from './get-request-url'; -import type { StartSpanOptions } from '../../types/startSpanOptions'; +import type { StartSpanOptions } from '@sentry/core'; /** * Build the initial span name and attributes for an outgoing HTTP request. diff --git a/packages/core/src/integrations/http/get-request-url.ts b/packages/server-utils/src/integrations/http/get-request-url.ts similarity index 100% rename from packages/core/src/integrations/http/get-request-url.ts rename to packages/server-utils/src/integrations/http/get-request-url.ts diff --git a/packages/core/src/integrations/http/index.ts b/packages/server-utils/src/integrations/http/index.ts similarity index 100% rename from packages/core/src/integrations/http/index.ts rename to packages/server-utils/src/integrations/http/index.ts diff --git a/packages/core/src/integrations/http/inject-trace-propagation-headers.ts b/packages/server-utils/src/integrations/http/inject-trace-propagation-headers.ts similarity index 86% rename from packages/core/src/integrations/http/inject-trace-propagation-headers.ts rename to packages/server-utils/src/integrations/http/inject-trace-propagation-headers.ts index 0324cabb81b2..833b491c8293 100644 --- a/packages/core/src/integrations/http/inject-trace-propagation-headers.ts +++ b/packages/server-utils/src/integrations/http/inject-trace-propagation-headers.ts @@ -1,14 +1,14 @@ -import type { LRUMap } from '../../utils/lru'; -import { getClient } from '../../currentScopes'; +import type { LRUMap } from '@sentry/core'; +import { getClient } from '@sentry/core'; import { DEBUG_BUILD } from '../../debug-build'; -import { debug } from '../../utils/debug-logger'; -import { isError } from '../../utils/is'; -import { getTraceData } from '../../utils/traceData'; -import { shouldPropagateTraceForUrl } from '../../utils/tracePropagationTargets'; +import { debug } from '@sentry/core'; +import { isError } from '@sentry/core'; +import { getTraceData } from '@sentry/core'; +import { shouldPropagateTraceForUrl } from '@sentry/core'; import { LOG_PREFIX } from './constants'; import { getRequestUrlFromClientRequest } from './get-request-url'; import type { HttpClientRequest } from './types'; -import { mergeBaggageHeaders } from '../../utils/baggage'; +import { mergeBaggageHeaders } from '@sentry/core'; /** * Inject Sentry trace-propagation headers into an outgoing request if the diff --git a/packages/core/src/integrations/http/patch-request-to-capture-body.ts b/packages/server-utils/src/integrations/http/patch-request-to-capture-body.ts similarity index 95% rename from packages/core/src/integrations/http/patch-request-to-capture-body.ts rename to packages/server-utils/src/integrations/http/patch-request-to-capture-body.ts index 2915fcc12dc3..3f30e673def4 100644 --- a/packages/core/src/integrations/http/patch-request-to-capture-body.ts +++ b/packages/server-utils/src/integrations/http/patch-request-to-capture-body.ts @@ -1,8 +1,8 @@ -import type { Scope } from '../../scope'; -import { debug } from '../../utils/debug-logger'; +import type { Scope } from '@sentry/core'; +import { debug } from '@sentry/core'; import { DEBUG_BUILD } from '../../debug-build'; import type { HttpIncomingMessage } from './types'; -import { getMaxBodyByteLength, type MaxRequestBodySize } from '../../utils/request'; +import { getMaxBodyByteLength, type MaxRequestBodySize } from '@sentry/core'; /** * This method patches the request object to capture the body. diff --git a/packages/core/src/integrations/http/record-request-session.ts b/packages/server-utils/src/integrations/http/record-request-session.ts similarity index 89% rename from packages/core/src/integrations/http/record-request-session.ts rename to packages/server-utils/src/integrations/http/record-request-session.ts index dfda6580cf16..4ecc77885e4c 100644 --- a/packages/core/src/integrations/http/record-request-session.ts +++ b/packages/server-utils/src/integrations/http/record-request-session.ts @@ -1,10 +1,15 @@ -import type { Client } from '../../client'; -import { debug } from '../../utils/debug-logger'; +import type { AggregationCounts, Client, Scope } from '@sentry/core'; +import { debug } from '@sentry/core'; import { DEBUG_BUILD } from '../../debug-build'; -import type { Scope } from '../../scope'; import type { HttpServerResponse } from './types'; -import type { AggregationCounts } from '../../types/session'; -import { safeUnref } from '../../utils/timer'; + +// Vendored from `@sentry/core`'s private `utils/timer.ts`. +function safeUnref unknown }>(timer: T): T { + if (typeof timer === 'object' && typeof timer.unref === 'function') { + timer.unref(); + } + return timer; +} const clientToRequestSessionAggregatesMap = new WeakMap< Client, diff --git a/packages/core/src/integrations/http/server-subscription.ts b/packages/server-utils/src/integrations/http/server-subscription.ts similarity index 96% rename from packages/core/src/integrations/http/server-subscription.ts rename to packages/server-utils/src/integrations/http/server-subscription.ts index 6d2aa67d01ef..d39a3ac7009d 100644 --- a/packages/core/src/integrations/http/server-subscription.ts +++ b/packages/server-utils/src/integrations/http/server-subscription.ts @@ -21,24 +21,24 @@ type ChannelListener = (message: unknown, name: string | symbol) => void; import { HTTP_ON_SERVER_REQUEST } from './constants'; import type { HttpIncomingMessage, HttpInstrumentationOptions, HttpServer, HttpServerResponse } from './types'; import { DEBUG_BUILD } from '../../debug-build'; -import { debug } from '../../utils/debug-logger'; -import { getClient, getCurrentScope, getIsolationScope, withIsolationScope } from '../../currentScopes'; -import { hasSpansEnabled } from '../../utils/hasSpansEnabled'; -import { headersToDict, httpHeadersToSpanAttributes, httpRequestToRequestData } from '../../utils/request'; +import { debug } from '@sentry/core'; +import { getClient, getCurrentScope, getIsolationScope, withIsolationScope } from '@sentry/core'; +import { hasSpansEnabled } from '@sentry/core'; +import { headersToDict, httpHeadersToSpanAttributes, httpRequestToRequestData } from '@sentry/core'; import { patchRequestToCaptureBody } from './patch-request-to-capture-body'; -import { parseStringToURLObject, stripUrlQueryAndFragment } from '../../utils/url'; +import { parseStringToURLObject, stripUrlQueryAndFragment } from '@sentry/core'; import { recordRequestSession } from './record-request-session'; -import { generateSpanId, generateTraceId } from '../../utils/propagationContext'; -import { continueTrace } from '../../tracing/trace'; -import { getSpanStatusFromHttpCode, SPAN_STATUS_ERROR, startSpanManual } from '../../tracing'; +import { generateSpanId, generateTraceId } from '@sentry/core'; +import { continueTrace } from '@sentry/core'; +import { getSpanStatusFromHttpCode, SPAN_STATUS_ERROR, startSpanManual } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, -} from '../../semanticAttributes'; -import { safeMathRandom } from '../../utils/randomSafeContext'; -import type { SpanAttributes } from '../../types/span'; -import type { SpanStatus } from '../../types/spanStatus'; +} from '@sentry/core'; +import { _INTERNAL_safeMathRandom as safeMathRandom } from '@sentry/core'; +import type { SpanAttributes } from '@sentry/core'; +import type { SpanStatus } from '@sentry/core'; // Tree-shakable guard to remove all code related to tracing declare const __SENTRY_TRACING__: boolean; diff --git a/packages/core/src/integrations/http/types.ts b/packages/server-utils/src/integrations/http/types.ts similarity index 99% rename from packages/core/src/integrations/http/types.ts rename to packages/server-utils/src/integrations/http/types.ts index 22538fb2dd84..372ea08fe115 100644 --- a/packages/core/src/integrations/http/types.ts +++ b/packages/server-utils/src/integrations/http/types.ts @@ -26,8 +26,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import type { RequestEventData } from '../../types/request'; -import type { Span } from '../../types/span'; +import type { RequestEventData } from '@sentry/core'; +import type { Span } from '@sentry/core'; /** Minimal interface for a Node.js http.ClientRequest */ export interface HttpClientRequest { diff --git a/packages/core/src/integrations/mcp-server/attributeExtraction.ts b/packages/server-utils/src/integrations/mcp-server/attributeExtraction.ts similarity index 98% rename from packages/core/src/integrations/mcp-server/attributeExtraction.ts rename to packages/server-utils/src/integrations/mcp-server/attributeExtraction.ts index 75449f43ccc9..7fe1a36b3d02 100644 --- a/packages/core/src/integrations/mcp-server/attributeExtraction.ts +++ b/packages/server-utils/src/integrations/mcp-server/attributeExtraction.ts @@ -2,7 +2,7 @@ * Core attribute extraction and building functions for MCP server instrumentation */ -import { isURLObjectRelative, parseStringToURLObject } from '../../utils/url'; +import { isURLObjectRelative, parseStringToURLObject } from '@sentry/core'; import { MCP_LOGGING_DATA_TYPE_ATTRIBUTE, MCP_LOGGING_LEVEL_ATTRIBUTE, diff --git a/packages/core/src/integrations/mcp-server/attributes.ts b/packages/server-utils/src/integrations/mcp-server/attributes.ts similarity index 100% rename from packages/core/src/integrations/mcp-server/attributes.ts rename to packages/server-utils/src/integrations/mcp-server/attributes.ts diff --git a/packages/core/src/integrations/mcp-server/correlation.ts b/packages/server-utils/src/integrations/mcp-server/correlation.ts similarity index 98% rename from packages/core/src/integrations/mcp-server/correlation.ts rename to packages/server-utils/src/integrations/mcp-server/correlation.ts index c527a34cd5a2..ba80cb77d13c 100644 --- a/packages/core/src/integrations/mcp-server/correlation.ts +++ b/packages/server-utils/src/integrations/mcp-server/correlation.ts @@ -10,8 +10,8 @@ * Falls back to WeakMap by transport instance for stateless transports (no sessionId). */ -import { SPAN_STATUS_ERROR } from '../../tracing'; -import type { Span } from '../../types/span'; +import { SPAN_STATUS_ERROR } from '@sentry/core'; +import type { Span } from '@sentry/core'; import { MCP_PROTOCOL_VERSION_ATTRIBUTE } from './attributes'; import { extractPromptResultAttributes, extractToolResultAttributes } from './resultExtraction'; import { buildServerAttributesFromInfo, extractSessionDataFromInitializeResponse } from './sessionExtraction'; diff --git a/packages/core/src/integrations/mcp-server/errorCapture.ts b/packages/server-utils/src/integrations/mcp-server/errorCapture.ts similarity index 85% rename from packages/core/src/integrations/mcp-server/errorCapture.ts rename to packages/server-utils/src/integrations/mcp-server/errorCapture.ts index 2ba401c93d08..6e205e2880c3 100644 --- a/packages/core/src/integrations/mcp-server/errorCapture.ts +++ b/packages/server-utils/src/integrations/mcp-server/errorCapture.ts @@ -5,10 +5,10 @@ * All capture operations are wrapped in try-catch to prevent side effects. */ -import { getClient } from '../../currentScopes'; -import { captureException } from '../../exports'; -import { SPAN_STATUS_ERROR } from '../../tracing'; -import { getActiveSpan } from '../../utils/spanUtils'; +import { getClient } from '@sentry/core'; +import { captureException } from '@sentry/core'; +import { SPAN_STATUS_ERROR } from '@sentry/core'; +import { getActiveSpan } from '@sentry/core'; import type { McpErrorType } from './types'; /** diff --git a/packages/core/src/integrations/mcp-server/handlers.ts b/packages/server-utils/src/integrations/mcp-server/handlers.ts similarity index 99% rename from packages/core/src/integrations/mcp-server/handlers.ts rename to packages/server-utils/src/integrations/mcp-server/handlers.ts index 200156a24093..a31521582a12 100644 --- a/packages/core/src/integrations/mcp-server/handlers.ts +++ b/packages/server-utils/src/integrations/mcp-server/handlers.ts @@ -6,8 +6,8 @@ */ import { DEBUG_BUILD } from '../../debug-build'; -import { debug } from '../../utils/debug-logger'; -import { fill } from '../../utils/object'; +import { debug } from '@sentry/core'; +import { fill } from '@sentry/core'; import { captureError } from './errorCapture'; import type { MCPHandler, MCPServerInstance } from './types'; diff --git a/packages/core/src/integrations/mcp-server/index.ts b/packages/server-utils/src/integrations/mcp-server/index.ts similarity index 97% rename from packages/core/src/integrations/mcp-server/index.ts rename to packages/server-utils/src/integrations/mcp-server/index.ts index 952e780c0a9f..24e1226d672f 100644 --- a/packages/core/src/integrations/mcp-server/index.ts +++ b/packages/server-utils/src/integrations/mcp-server/index.ts @@ -1,5 +1,5 @@ -import { getClient } from '../../currentScopes'; -import { fill } from '../../utils/object'; +import { getClient } from '@sentry/core'; +import { fill } from '@sentry/core'; import { wrapAllMCPHandlers, wrapExistingHandlers } from './handlers'; import { wrapTransportError, wrapTransportOnClose, wrapTransportOnMessage, wrapTransportSend } from './transport'; import type { MCPServerInstance, McpServerWrapperOptions, MCPTransport, ResolvedMcpOptions } from './types'; diff --git a/packages/core/src/integrations/mcp-server/methodConfig.ts b/packages/server-utils/src/integrations/mcp-server/methodConfig.ts similarity index 100% rename from packages/core/src/integrations/mcp-server/methodConfig.ts rename to packages/server-utils/src/integrations/mcp-server/methodConfig.ts diff --git a/packages/core/src/integrations/mcp-server/piiFiltering.ts b/packages/server-utils/src/integrations/mcp-server/piiFiltering.ts similarity index 96% rename from packages/core/src/integrations/mcp-server/piiFiltering.ts rename to packages/server-utils/src/integrations/mcp-server/piiFiltering.ts index cfc5f365e976..3a5b14805512 100644 --- a/packages/core/src/integrations/mcp-server/piiFiltering.ts +++ b/packages/server-utils/src/integrations/mcp-server/piiFiltering.ts @@ -5,7 +5,7 @@ * Input/output data (request arguments, tool/prompt results) is controlled * separately via recordInputs/recordOutputs options. */ -import type { SpanAttributeValue } from '../../types/span'; +import type { SpanAttributeValue } from '@sentry/core'; import { CLIENT_ADDRESS_ATTRIBUTE, CLIENT_PORT_ATTRIBUTE, MCP_RESOURCE_URI_ATTRIBUTE } from './attributes'; /** diff --git a/packages/core/src/integrations/mcp-server/resultExtraction.ts b/packages/server-utils/src/integrations/mcp-server/resultExtraction.ts similarity index 100% rename from packages/core/src/integrations/mcp-server/resultExtraction.ts rename to packages/server-utils/src/integrations/mcp-server/resultExtraction.ts diff --git a/packages/core/src/integrations/mcp-server/sessionExtraction.ts b/packages/server-utils/src/integrations/mcp-server/sessionExtraction.ts similarity index 100% rename from packages/core/src/integrations/mcp-server/sessionExtraction.ts rename to packages/server-utils/src/integrations/mcp-server/sessionExtraction.ts diff --git a/packages/core/src/integrations/mcp-server/sessionManagement.ts b/packages/server-utils/src/integrations/mcp-server/sessionManagement.ts similarity index 100% rename from packages/core/src/integrations/mcp-server/sessionManagement.ts rename to packages/server-utils/src/integrations/mcp-server/sessionManagement.ts diff --git a/packages/core/src/integrations/mcp-server/spans.ts b/packages/server-utils/src/integrations/mcp-server/spans.ts similarity index 97% rename from packages/core/src/integrations/mcp-server/spans.ts rename to packages/server-utils/src/integrations/mcp-server/spans.ts index 010148faab65..89476b839290 100644 --- a/packages/core/src/integrations/mcp-server/spans.ts +++ b/packages/server-utils/src/integrations/mcp-server/spans.ts @@ -5,13 +5,13 @@ * Handles both request and notification spans with attribute extraction. */ -import { getClient } from '../../currentScopes'; +import { getClient } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, -} from '../../semanticAttributes'; -import { startSpan } from '../../tracing'; +} from '@sentry/core'; +import { startSpan } from '@sentry/core'; import { buildTransportAttributes, buildTypeSpecificAttributes } from './attributeExtraction'; import { MCP_FUNCTION_ORIGIN_VALUE, diff --git a/packages/core/src/integrations/mcp-server/transport.ts b/packages/server-utils/src/integrations/mcp-server/transport.ts similarity index 97% rename from packages/core/src/integrations/mcp-server/transport.ts rename to packages/server-utils/src/integrations/mcp-server/transport.ts index 49b141964fa9..04343d224e7b 100644 --- a/packages/core/src/integrations/mcp-server/transport.ts +++ b/packages/server-utils/src/integrations/mcp-server/transport.ts @@ -5,9 +5,9 @@ * @see https://modelcontextprotocol.io/specification/2025-06-18/basic/transports */ -import { getIsolationScope, withIsolationScope } from '../../currentScopes'; -import { startInactiveSpan, withActiveSpan } from '../../tracing'; -import { fill } from '../../utils/object'; +import { getIsolationScope, withIsolationScope } from '@sentry/core'; +import { startInactiveSpan, withActiveSpan } from '@sentry/core'; +import { fill } from '@sentry/core'; import { MCP_PROTOCOL_VERSION_ATTRIBUTE } from './attributes'; import { cleanupPendingSpansForTransport, completeSpanWithResults, storeSpanForRequest } from './correlation'; import { captureError } from './errorCapture'; diff --git a/packages/core/src/integrations/mcp-server/types.ts b/packages/server-utils/src/integrations/mcp-server/types.ts similarity index 99% rename from packages/core/src/integrations/mcp-server/types.ts rename to packages/server-utils/src/integrations/mcp-server/types.ts index 9706ddcf3b54..058f13a05c25 100644 --- a/packages/core/src/integrations/mcp-server/types.ts +++ b/packages/server-utils/src/integrations/mcp-server/types.ts @@ -1,4 +1,4 @@ -import type { Span } from '../../types/span'; +import type { Span } from '@sentry/core'; /** Types for MCP server instrumentation */ diff --git a/packages/core/src/integrations/mcp-server/validation.ts b/packages/server-utils/src/integrations/mcp-server/validation.ts similarity index 98% rename from packages/core/src/integrations/mcp-server/validation.ts rename to packages/server-utils/src/integrations/mcp-server/validation.ts index 15fb27f9c803..83b1d70a43cc 100644 --- a/packages/core/src/integrations/mcp-server/validation.ts +++ b/packages/server-utils/src/integrations/mcp-server/validation.ts @@ -5,7 +5,7 @@ */ import { DEBUG_BUILD } from '../../debug-build'; -import { debug } from '../../utils/debug-logger'; +import { debug } from '@sentry/core'; import type { JsonRpcNotification, JsonRpcRequest, JsonRpcResponse } from './types'; /** diff --git a/packages/core/src/integrations/postgresjs.ts b/packages/server-utils/src/integrations/postgresjs.ts similarity index 98% rename from packages/core/src/integrations/postgresjs.ts rename to packages/server-utils/src/integrations/postgresjs.ts index bb45aedbc4b0..ee2f6f747242 100644 --- a/packages/core/src/integrations/postgresjs.ts +++ b/packages/server-utils/src/integrations/postgresjs.ts @@ -2,12 +2,15 @@ // This can be used in any environment (Node.js, Cloudflare Workers, etc.) // without depending on OpenTelemetry module hooking. +import { + debug, + getActiveSpan, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SPAN_STATUS_ERROR, + type Span, + startSpanManual, +} from '@sentry/core'; import { DEBUG_BUILD } from '../debug-build'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN } from '../semanticAttributes'; -import { SPAN_STATUS_ERROR, startSpanManual } from '../tracing'; -import type { Span } from '../types/span'; -import { debug } from '../utils/debug-logger'; -import { getActiveSpan } from '../utils/spanUtils'; const SQL_OPERATION_REGEX = /^(SELECT|INSERT|UPDATE|DELETE|CREATE|DROP|ALTER)/i; diff --git a/packages/core/src/server-runtime-client.ts b/packages/server-utils/src/server-runtime-client.ts similarity index 87% rename from packages/core/src/server-runtime-client.ts rename to packages/server-utils/src/server-runtime-client.ts index 26ae3e80f3b1..fd34714192e5 100644 --- a/packages/core/src/server-runtime-client.ts +++ b/packages/server-utils/src/server-runtime-client.ts @@ -1,22 +1,29 @@ -import { createCheckInEnvelope } from './checkin'; -import { Client } from './client'; -import { getIsolationScope } from './currentScopes'; +import { + _getTraceInfoFromScope, + addUserAgentToTransportHeaders, + type BaseTransportOptions, + type CheckIn, + Client, + type ClientOptions, + createCheckInEnvelope, + debug, + DEFAULT_TRANSPORT_BUFFER_SIZE, + type Event, + type EventHint, + eventFromMessage, + eventFromUnknownInput, + getIsolationScope, + makePromiseBuffer, + type MonitorConfig, + type ParameterizedString, + resolvedSyncPromise, + type Scope, + type SerializedCheckIn, + type SeverityLevel, + type Transport, + uuid4, +} from '@sentry/core'; import { DEBUG_BUILD } from './debug-build'; -import type { Scope } from './scope'; -import { DEFAULT_TRANSPORT_BUFFER_SIZE } from './transports/base'; -import { addUserAgentToTransportHeaders } from './transports/userAgent'; -import type { CheckIn, MonitorConfig, SerializedCheckIn } from './types/checkin'; -import type { Event, EventHint } from './types/event'; -import type { ClientOptions } from './types/options'; -import type { ParameterizedString } from './types/parameterize'; -import type { SeverityLevel } from './types/severity'; -import type { BaseTransportOptions, Transport } from './types/transport'; -import { debug } from './utils/debug-logger'; -import { eventFromMessage, eventFromUnknownInput } from './utils/eventbuilder'; -import { uuid4 } from './utils/misc'; -import { makePromiseBuffer } from './utils/promisebuffer'; -import { resolvedSyncPromise } from './utils/syncpromise'; -import { _getTraceInfoFromScope } from './utils/trace-info'; export interface ServerRuntimeClientOptions extends ClientOptions { platform?: string; diff --git a/packages/core/src/trpc.ts b/packages/server-utils/src/trpc.ts similarity index 88% rename from packages/core/src/trpc.ts rename to packages/server-utils/src/trpc.ts index 53c55bca3c32..853a8f3c423b 100644 --- a/packages/core/src/trpc.ts +++ b/packages/server-utils/src/trpc.ts @@ -1,9 +1,13 @@ -import { getClient, withIsolationScope } from './currentScopes'; -import { captureException } from './exports'; -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from './semanticAttributes'; -import { startSpanManual } from './tracing'; -import { normalize } from './utils/normalize'; -import { setNormalizationDepthOverrideHint } from './utils/normalizationHints'; +import { + captureException, + getClient, + normalize, + SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, + SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, + setNormalizationDepthOverrideHint, + startSpanManual, + withIsolationScope, +} from '@sentry/core'; interface SentryTrpcMiddlewareOptions { /** Whether to include procedure inputs in reported events. Defaults to `false`. */ diff --git a/packages/server-utils/src/types/server-runtime-options.ts b/packages/server-utils/src/types/server-runtime-options.ts new file mode 100644 index 000000000000..c70625fce66c --- /dev/null +++ b/packages/server-utils/src/types/server-runtime-options.ts @@ -0,0 +1,90 @@ +import type { TracePropagationTargets } from '@sentry/core'; + +/** + * Base options for WinterTC-compatible server-side JavaScript runtimes. + * This interface contains common configuration options shared between + * SDKs. + */ +export interface ServerRuntimeOptions { + /** + * List of strings/regex controlling to which outgoing requests + * the SDK will attach tracing headers. + * + * By default the SDK will attach those headers to all outgoing + * requests. If this option is provided, the SDK will match the + * request URL of outgoing requests against the items in this + * array, and only attach tracing headers if a match was found. + * + * @example + * ```js + * Sentry.init({ + * tracePropagationTargets: ['api.site.com'], + * }); + * ``` + */ + tracePropagationTargets?: TracePropagationTargets; + + /** + * Sets an optional server name (device name). + * + * This is useful for identifying which server or instance is sending events. + */ + serverName?: string; + + /** + * If you use Spotlight by Sentry during development, use + * this option to forward captured Sentry events to Spotlight. + * + * Either set it to true, or provide a specific Spotlight Sidecar URL. + * + * More details: https://spotlightjs.com/ + * + * IMPORTANT: Only set this option to `true` while developing, not in production! + */ + spotlight?: boolean | string; + + /** + * If set to `false`, the SDK will not automatically detect the `serverName`. + * + * This is useful if you are using the SDK in a CLI app or Electron where the + * hostname might be considered PII. + * + * @default true + */ + includeServerName?: boolean; + + /** + * By default, the SDK will try to identify problems with your instrumentation setup and warn you about it. + * If you want to disable these warnings, set this to `true`. + */ + disableInstrumentationWarnings?: boolean; + + /** + * Controls how many milliseconds to wait before shutting down. The default is 2 seconds. Setting this too low can cause + * problems for sending events from command line applications. Setting it too + * high can cause the application to block for users with network connectivity + * problems. + */ + shutdownTimeout?: number; + + /** + * Configures in which interval client reports will be flushed. Defaults to `60_000` (milliseconds). + */ + clientReportFlushInterval?: number; + + /** + * The max. duration in seconds that the SDK will wait for parent spans to be finished before discarding a span. + * The SDK will automatically clean up spans that have no finished parent after this duration. + * This is necessary to prevent memory leaks in case of parent spans that are never finished or otherwise dropped/missing. + * However, if you have very long-running spans in your application, a shorter duration might cause spans to be discarded too early. + * In this case, you can increase this duration to a value that fits your expected data. + * + * Defaults to 300 seconds (5 minutes). + */ + maxSpanWaitDuration?: number; + + /** + * Callback that is executed when a fatal global error occurs. + */ + onFatalError?(this: void, error: Error): void; +} diff --git a/packages/core/test/lib/integrations/express/index.test.ts b/packages/server-utils/test/integrations/express/index.test.ts similarity index 93% rename from packages/core/test/lib/integrations/express/index.test.ts rename to packages/server-utils/test/integrations/express/index.test.ts index 9d4a78cd3244..efd21daa0121 100644 --- a/packages/core/test/lib/integrations/express/index.test.ts +++ b/packages/server-utils/test/integrations/express/index.test.ts @@ -2,7 +2,7 @@ import { patchExpressModule, expressErrorHandler, setupExpressErrorHandler, -} from '../../../../src/integrations/express/index'; +} from '../../../src/integrations/express/index'; import { describe, it, expect, vi, beforeEach } from 'vitest'; import type { Mock } from 'vitest'; @@ -20,8 +20,8 @@ import type { ExpressMiddleware, ExpressErrorMiddleware, ExpressHandlerOptions, -} from '../../../../src/integrations/express/types'; -import type { WrappedFunction } from '../../../../src/types/wrappedfunction'; +} from '../../../src/integrations/express/types'; +import type { WrappedFunction } from '@sentry/core'; const sdkProcessingMetadata: unknown[] = []; const isolationScope = { @@ -34,38 +34,39 @@ const isolationScope = { }, }; -vi.mock('../../../../src/currentScopes', () => ({ - getIsolationScope() { - return isolationScope; - }, -})); - const capturedExceptions: [unknown, unknown][] = []; -vi.mock('../../../../src/exports', () => ({ - captureException(error: unknown, hint: unknown) { - capturedExceptions.push([error, hint]); - return 'eventId'; - }, -})); - -vi.mock('../../../../src/debug-build', () => ({ - DEBUG_BUILD: true, -})); const debugErrors: [string, Error][] = []; const debugWarnings: string[] = []; -vi.mock('../../../../src/utils/debug-logger', () => ({ - debug: { - warn: (msg: string) => debugWarnings.push(msg), - error: (msg: string, er: Error) => { - debugErrors.push([msg, er]); + +vi.mock('@sentry/core', async () => { + const actual = await vi.importActual('@sentry/core'); + return { + ...actual, + getIsolationScope() { + return isolationScope; }, - }, + captureException(error: unknown, hint: unknown) { + capturedExceptions.push([error, hint]); + return 'eventId'; + }, + debug: { + ...actual.debug, + warn: (msg: string) => debugWarnings.push(msg), + error: (msg: string, er: Error) => { + debugErrors.push([msg, er]); + }, + }, + }; +}); + +vi.mock('../../../src/debug-build', () => ({ + DEBUG_BUILD: true, })); beforeEach(() => (patchLayerCalls.length = 0)); const patchLayerCalls: [getOptions: () => ExpressIntegrationOptions, layer: ExpressLayer, layerPath?: string][] = []; -vi.mock('../../../../src/integrations/express/patch-layer', () => ({ +vi.mock('../../../src/integrations/express/patch-layer', () => ({ patchLayer: (getOptions: () => ExpressIntegrationOptions, layer?: ExpressLayer, layerPath?: string) => { if (layer) { patchLayerCalls.push([getOptions, layer, layerPath]); diff --git a/packages/core/test/lib/integrations/express/patch-layer.test.ts b/packages/server-utils/test/integrations/express/patch-layer.test.ts similarity index 91% rename from packages/core/test/lib/integrations/express/patch-layer.test.ts rename to packages/server-utils/test/integrations/express/patch-layer.test.ts index 3c44bd93836f..4f0e01992358 100644 --- a/packages/core/test/lib/integrations/express/patch-layer.test.ts +++ b/packages/server-utils/test/integrations/express/patch-layer.test.ts @@ -1,20 +1,20 @@ import { describe, beforeEach, it, expect, vi } from 'vitest'; -import { type ExpressPatchLayerOptions, patchLayer } from '../../../../src/integrations/express/patch-layer'; +import { type ExpressPatchLayerOptions, patchLayer } from '../../../src/integrations/express/patch-layer'; import { type ExpressRequest, type ExpressLayer, type ExpressResponse, -} from '../../../../src/integrations/express/types'; -import { getStoredLayers, storeLayer } from '../../../../src/integrations/express/request-layer-store'; -import { type StartSpanOptions } from '../../../../src/types/startSpanOptions'; -import { type Span } from '../../../../src/types/span'; +} from '../../../src/integrations/express/types'; +import { getStoredLayers, storeLayer } from '../../../src/integrations/express/request-layer-store'; +import { type StartSpanOptions } from '@sentry/core'; +import { type Span } from '@sentry/core'; import { EventEmitter } from 'node:events'; -import { getOriginalFunction, markFunctionWrapped } from '../../../../src'; +import { getOriginalFunction, markFunctionWrapped } from '@sentry/core'; // must be var to hoist above vi.mock var DEBUG_BUILD = true; beforeEach(() => (DEBUG_BUILD = true)); -vi.mock('../../../../src/debug-build', () => ({ +vi.mock('../../../src/debug-build', () => ({ get DEBUG_BUILD() { return DEBUG_BUILD ?? true; }, @@ -22,13 +22,6 @@ vi.mock('../../../../src/debug-build', () => ({ const warnings: string[] = []; beforeEach(() => (warnings.length = 0)); -vi.mock('../../../../src/utils/debug-logger', () => ({ - debug: { - warn(msg: string) { - warnings.push(msg); - }, - }, -})); let inDefaultIsolationScope = false; beforeEach(() => (inDefaultIsolationScope = false)); @@ -52,16 +45,6 @@ const defaultIsolationScope = { this._scopeData.sdkProcessingMetadata = data; }, }; -vi.mock('../../../../src/currentScopes', () => ({ - getIsolationScope() { - return inDefaultIsolationScope ? defaultIsolationScope : notDefaultIsolationScope; - }, -})); -vi.mock('../../../../src/defaultScopes', () => ({ - getDefaultIsolationScope() { - return defaultIsolationScope; - }, -})); const mockSpans: MockSpan[] = []; beforeEach(() => (mockSpans.length = 0)); @@ -127,25 +110,38 @@ const checkSpans = (expectations: Partial[]) => { let hasActiveSpan = true; const parentSpan = {}; -vi.mock('../../../../src/utils/spanUtils', async () => ({ - ...(await import('../../../../src/utils/spanUtils')), - getActiveSpan() { - return hasActiveSpan ? parentSpan : undefined; - }, -})); -vi.mock('../../../../src/tracing', () => ({ - SPAN_STATUS_ERROR: 2, - withActiveSpan(span: unknown, cb: Function) { - expect(span).toBe(parentSpan); - return cb(); - }, - startSpanManual(options: StartSpanOptions, callback: (span: Span) => T): T { - const span = new MockSpan(options); - mockSpans.push(span); - return callback(span as unknown as Span); - }, -})); +vi.mock('@sentry/core', async () => { + const actual = await vi.importActual('@sentry/core'); + return { + ...actual, + debug: { + ...actual.debug, + warn(msg: string) { + warnings.push(msg); + }, + }, + getIsolationScope() { + return inDefaultIsolationScope ? defaultIsolationScope : notDefaultIsolationScope; + }, + getDefaultIsolationScope() { + return defaultIsolationScope; + }, + getActiveSpan() { + return hasActiveSpan ? parentSpan : undefined; + }, + SPAN_STATUS_ERROR: 2, + withActiveSpan(span: unknown, cb: Function) { + expect(span).toBe(parentSpan); + return cb(); + }, + startSpanManual(options: StartSpanOptions, callback: (span: Span) => T): T { + const span = new MockSpan(options); + mockSpans.push(span); + return callback(span as unknown as Span); + }, + }; +}); describe('patchLayer', () => { describe('no-ops', () => { @@ -361,10 +357,8 @@ describe('patchLayer', () => { it('sets tx name in isolation scope', async () => { DEBUG_BUILD = true; - expect( - (await import('../../../../src/currentScopes')).getIsolationScope() === - (await import('../../../../src/defaultScopes')).getDefaultIsolationScope(), - ).toBe(false); + const sentryCore = await import('@sentry/core'); + expect(sentryCore.getIsolationScope() === sentryCore.getDefaultIsolationScope()).toBe(false); const options: ExpressPatchLayerOptions = {}; const req = Object.assign(new EventEmitter(), { diff --git a/packages/core/test/lib/integrations/express/request-layer-store.test.ts b/packages/server-utils/test/integrations/express/request-layer-store.test.ts similarity index 74% rename from packages/core/test/lib/integrations/express/request-layer-store.test.ts rename to packages/server-utils/test/integrations/express/request-layer-store.test.ts index c2f58ac0e6f4..9e2499a9d55c 100644 --- a/packages/core/test/lib/integrations/express/request-layer-store.test.ts +++ b/packages/server-utils/test/integrations/express/request-layer-store.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from 'vitest'; -import type { ExpressRequest } from '../../../../src/integrations/express/types'; -import { getStoredLayers, storeLayer } from '../../../../src/integrations/express/request-layer-store'; +import type { ExpressRequest } from '../../../src/integrations/express/types'; +import { getStoredLayers, storeLayer } from '../../../src/integrations/express/request-layer-store'; describe('storeLayer', () => { it('handles case when nothing stored yet', () => { diff --git a/packages/core/test/lib/integrations/express/set-sdk-processing-metadata.test.ts b/packages/server-utils/test/integrations/express/set-sdk-processing-metadata.test.ts similarity index 77% rename from packages/core/test/lib/integrations/express/set-sdk-processing-metadata.test.ts rename to packages/server-utils/test/integrations/express/set-sdk-processing-metadata.test.ts index 21a6810b4279..92f32a0c2de7 100644 --- a/packages/core/test/lib/integrations/express/set-sdk-processing-metadata.test.ts +++ b/packages/server-utils/test/integrations/express/set-sdk-processing-metadata.test.ts @@ -1,5 +1,5 @@ import { vi, beforeEach, describe, it, expect } from 'vitest'; -import { setSDKProcessingMetadata } from '../../../../src/integrations/express/set-sdk-processing-metadata'; +import { setSDKProcessingMetadata } from '../../../src/integrations/express/set-sdk-processing-metadata'; const sdkProcessingMetadatas: unknown[] = []; beforeEach(() => (sdkProcessingMetadatas.length = 0)); @@ -13,11 +13,15 @@ const isolationScope = { sdkProcessingMetadatas.push(data); }, }; -vi.mock('../../../../src/currentScopes', () => ({ - getIsolationScope() { - return isolationScope; - }, -})); +vi.mock('@sentry/core', async () => { + const actual = await vi.importActual('@sentry/core'); + return { + ...actual, + getIsolationScope() { + return isolationScope; + }, + }; +}); describe('setSDKProcessingMetadata', () => { it('sets the normalized request data', () => { diff --git a/packages/core/test/lib/integrations/express/types.test.ts b/packages/server-utils/test/integrations/express/types.test.ts similarity index 89% rename from packages/core/test/lib/integrations/express/types.test.ts rename to packages/server-utils/test/integrations/express/types.test.ts index 12fe68864b3d..0bcb0e30ad84 100644 --- a/packages/core/test/lib/integrations/express/types.test.ts +++ b/packages/server-utils/test/integrations/express/types.test.ts @@ -1,4 +1,4 @@ -import * as types from '../../../../src/integrations/express/types'; +import * as types from '../../../src/integrations/express/types'; import { describe, it, expect } from 'vitest'; // this is mostly just a types-bag, but it does have some constant keys diff --git a/packages/core/test/lib/integrations/express/utils.test.ts b/packages/server-utils/test/integrations/express/utils.test.ts similarity index 98% rename from packages/core/test/lib/integrations/express/utils.test.ts rename to packages/server-utils/test/integrations/express/utils.test.ts index a7ec32d96e8d..b5619200574b 100644 --- a/packages/core/test/lib/integrations/express/utils.test.ts +++ b/packages/server-utils/test/integrations/express/utils.test.ts @@ -1,4 +1,4 @@ -import { storeLayer } from '../../../../src/integrations/express/request-layer-store'; +import { storeLayer } from '../../../src/integrations/express/request-layer-store'; import { ATTR_EXPRESS_NAME, ATTR_EXPRESS_TYPE, @@ -6,7 +6,7 @@ import { type ExpressIntegrationOptions, type ExpressLayer, type ExpressRequest, -} from '../../../../src/integrations/express/types'; +} from '../../../src/integrations/express/types'; import { asErrorAndMessage, defaultShouldHandleError, @@ -19,7 +19,7 @@ import { isExpressWithRouterPrototype, isLayerIgnored, isRoutePattern, -} from '../../../../src/integrations/express/utils'; +} from '../../../src/integrations/express/utils'; import { describe, it, expect } from 'vitest'; diff --git a/packages/core/test/lib/integrations/http/add-outgoing-request-breadcrumb.test.ts b/packages/server-utils/test/integrations/http/add-outgoing-request-breadcrumb.test.ts similarity index 96% rename from packages/core/test/lib/integrations/http/add-outgoing-request-breadcrumb.test.ts rename to packages/server-utils/test/integrations/http/add-outgoing-request-breadcrumb.test.ts index 8ed6a1f3d660..3d9a1db2b0e3 100644 --- a/packages/core/test/lib/integrations/http/add-outgoing-request-breadcrumb.test.ts +++ b/packages/server-utils/test/integrations/http/add-outgoing-request-breadcrumb.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import * as breadcrumbsModule from '../../../../src/breadcrumbs'; -import { addOutgoingRequestBreadcrumb } from '../../../../src/integrations/http/add-outgoing-request-breadcrumb'; -import type { HttpClientRequest, HttpIncomingMessage } from '../../../../src/integrations/http/types'; +import * as breadcrumbsModule from '@sentry/core'; +import { addOutgoingRequestBreadcrumb } from '../../../src/integrations/http/add-outgoing-request-breadcrumb'; +import type { HttpClientRequest, HttpIncomingMessage } from '../../../src/integrations/http/types'; function makeMockRequest(overrides: Partial> = {}): HttpClientRequest { return { diff --git a/packages/core/test/lib/integrations/http/client-patch.test.ts b/packages/server-utils/test/integrations/http/client-patch.test.ts similarity index 90% rename from packages/core/test/lib/integrations/http/client-patch.test.ts rename to packages/server-utils/test/integrations/http/client-patch.test.ts index 4c50c46b61c2..932e0d50b0a7 100644 --- a/packages/core/test/lib/integrations/http/client-patch.test.ts +++ b/packages/server-utils/test/integrations/http/client-patch.test.ts @@ -1,12 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import { HTTP_ON_CLIENT_REQUEST } from '../../../../src/integrations/http/constants'; -import { patchHttpModuleClient } from '../../../../src/integrations/http/client-patch'; -import type { HttpClientRequest, HttpExport } from '../../../../src/integrations/http/types'; -import { getOriginalFunction } from '../../../../src/utils/object'; +import { HTTP_ON_CLIENT_REQUEST } from '../../../src/integrations/http/constants'; +import { patchHttpModuleClient } from '../../../src/integrations/http/client-patch'; +import type { HttpClientRequest, HttpExport } from '../../../src/integrations/http/types'; +import { getOriginalFunction } from '@sentry/core'; const mockClientRequestHandler = vi.fn(); -vi.mock('../../../../src/integrations/http/client-subscriptions', () => ({ +vi.mock('../../../src/integrations/http/client-subscriptions', () => ({ getHttpClientSubscriptions: vi.fn(() => ({ [HTTP_ON_CLIENT_REQUEST]: mockClientRequestHandler, })), diff --git a/packages/core/test/lib/integrations/http/client-subscriptions.test.ts b/packages/server-utils/test/integrations/http/client-subscriptions.test.ts similarity index 89% rename from packages/core/test/lib/integrations/http/client-subscriptions.test.ts rename to packages/server-utils/test/integrations/http/client-subscriptions.test.ts index 46b486368cdc..22f6a24fcad7 100644 --- a/packages/core/test/lib/integrations/http/client-subscriptions.test.ts +++ b/packages/server-utils/test/integrations/http/client-subscriptions.test.ts @@ -1,10 +1,10 @@ import { afterEach, describe, expect, it, vi } from 'vitest'; -import * as breadcrumbModule from '../../../../src/integrations/http/add-outgoing-request-breadcrumb'; -import { HTTP_ON_CLIENT_REQUEST } from '../../../../src/integrations/http/constants'; -import { getHttpClientSubscriptions } from '../../../../src/integrations/http/client-subscriptions'; -import type { HttpClientRequest, HttpIncomingMessage } from '../../../../src/integrations/http/types'; -import { SUPPRESS_TRACING_KEY } from '../../../../src/tracing'; -import { getCurrentScope, withScope } from '../../../../src/currentScopes'; +import * as breadcrumbModule from '../../../src/integrations/http/add-outgoing-request-breadcrumb'; +import { HTTP_ON_CLIENT_REQUEST } from '../../../src/integrations/http/constants'; +import { getHttpClientSubscriptions } from '../../../src/integrations/http/client-subscriptions'; +import type { HttpClientRequest, HttpIncomingMessage } from '../../../src/integrations/http/types'; +import { SUPPRESS_TRACING_KEY } from '@sentry/core'; +import { getCurrentScope, withScope } from '@sentry/core'; function makeMockRequest(): HttpClientRequest & { _responseListeners: ((res: HttpIncomingMessage) => void)[]; diff --git a/packages/core/test/lib/integrations/http/constants.test.ts b/packages/server-utils/test/integrations/http/constants.test.ts similarity index 91% rename from packages/core/test/lib/integrations/http/constants.test.ts rename to packages/server-utils/test/integrations/http/constants.test.ts index 6a63e74ba5c6..8315e7741342 100644 --- a/packages/core/test/lib/integrations/http/constants.test.ts +++ b/packages/server-utils/test/integrations/http/constants.test.ts @@ -3,7 +3,7 @@ import { HTTP_ON_CLIENT_REQUEST, HTTP_ON_SERVER_REQUEST, LOG_PREFIX, -} from '../../../../src/integrations/http/constants'; +} from '../../../src/integrations/http/constants'; describe('http constants', () => { it('LOG_PREFIX is the expected string', () => { diff --git a/packages/core/test/lib/integrations/http/double-wrap-warning.test.ts b/packages/server-utils/test/integrations/http/double-wrap-warning.test.ts similarity index 69% rename from packages/core/test/lib/integrations/http/double-wrap-warning.test.ts rename to packages/server-utils/test/integrations/http/double-wrap-warning.test.ts index 34108bbe5111..3a09123bdd9b 100644 --- a/packages/core/test/lib/integrations/http/double-wrap-warning.test.ts +++ b/packages/server-utils/test/integrations/http/double-wrap-warning.test.ts @@ -1,19 +1,24 @@ -import { it, expect, describe, vi } from 'vitest'; -import { doubleWrapWarning, warning } from '../../../../src/integrations/http/double-wrap-warning'; -import type { HttpModuleExport } from '../../../../src/integrations/http/types'; +import { describe, expect, it, vi } from 'vitest'; +import { doubleWrapWarning, warning } from '../../../src/integrations/http/double-wrap-warning'; +import type { HttpModuleExport } from '../../../src/integrations/http/types'; const DEBUG_WARNS: string[] = []; -vi.mock('../../../../src/utils/debug-logger', () => ({ - debug: { - warn: (msg: string) => { - DEBUG_WARNS.push(msg); +vi.mock('@sentry/core', async () => { + const actual = await vi.importActual('@sentry/core'); + return { + ...actual, + debug: { + ...actual.debug, + warn: (msg: string) => { + DEBUG_WARNS.push(msg); + }, }, - }, -})); + }; +}); // must be var, because vi.mock hoists var debugBuild: boolean = true; -vi.mock(import('../../../../src/debug-build'), () => ({ +vi.mock(import('../../../src/debug-build'), () => ({ get DEBUG_BUILD() { return debugBuild ?? true; }, @@ -48,7 +53,7 @@ describe('doubleWrapWarning', () => { it('is a no-op if not in debug mode', async () => { vi.resetModules(); debugBuild = false; - const { doubleWrapWarning } = await import('../../../../src/integrations/http/double-wrap-warning'); + const { doubleWrapWarning } = await import('../../../src/integrations/http/double-wrap-warning'); doubleWrapWarning({ request: Object.assign(() => {}, { __unwrap() {} }), get: Object.assign(() => {}, { __unwrap() {} }), diff --git a/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts b/packages/server-utils/test/integrations/http/get-outgoing-span-data.test.ts similarity index 97% rename from packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts rename to packages/server-utils/test/integrations/http/get-outgoing-span-data.test.ts index fc2527ac7732..2ca418de268d 100644 --- a/packages/core/test/lib/integrations/http/get-outgoing-span-data.test.ts +++ b/packages/server-utils/test/integrations/http/get-outgoing-span-data.test.ts @@ -2,9 +2,9 @@ import { describe, expect, it, vi } from 'vitest'; import { getOutgoingRequestSpanData, setIncomingResponseSpanData, -} from '../../../../src/integrations/http/get-outgoing-span-data'; -import type { HttpClientRequest, HttpIncomingMessage } from '../../../../src/integrations/http/types'; -import type { Span } from '../../../../src/types/span'; +} from '../../../src/integrations/http/get-outgoing-span-data'; +import type { HttpClientRequest, HttpIncomingMessage } from '../../../src/integrations/http/types'; +import type { Span } from '@sentry/core'; function makeMockRequest(overrides: Partial> = {}): HttpClientRequest { return { diff --git a/packages/core/test/lib/integrations/http/get-request-url.test.ts b/packages/server-utils/test/integrations/http/get-request-url.test.ts similarity index 95% rename from packages/core/test/lib/integrations/http/get-request-url.test.ts rename to packages/server-utils/test/integrations/http/get-request-url.test.ts index 55bc1ba90f3a..525c392325d8 100644 --- a/packages/core/test/lib/integrations/http/get-request-url.test.ts +++ b/packages/server-utils/test/integrations/http/get-request-url.test.ts @@ -1,6 +1,6 @@ import { it, describe, expect } from 'vitest'; -import { getRequestUrlFromClientRequest, getRequestUrl } from '../../../../src/integrations/http/get-request-url'; -import type { HttpClientRequest, HttpRequestOptions } from '../../../../src/integrations/http/types'; +import { getRequestUrlFromClientRequest, getRequestUrl } from '../../../src/integrations/http/get-request-url'; +import type { HttpClientRequest, HttpRequestOptions } from '../../../src/integrations/http/types'; describe('getRequestUrl', () => { it.each([ diff --git a/packages/core/test/lib/integrations/http/inject-trace-propagation-headers.test.ts b/packages/server-utils/test/integrations/http/inject-trace-propagation-headers.test.ts similarity index 87% rename from packages/core/test/lib/integrations/http/inject-trace-propagation-headers.test.ts rename to packages/server-utils/test/integrations/http/inject-trace-propagation-headers.test.ts index 3338d066328f..34d66e887f4d 100644 --- a/packages/core/test/lib/integrations/http/inject-trace-propagation-headers.test.ts +++ b/packages/server-utils/test/integrations/http/inject-trace-propagation-headers.test.ts @@ -1,27 +1,28 @@ +import { LRUMap } from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { injectTracePropagationHeaders } from '../../../../src/integrations/http/inject-trace-propagation-headers'; -import type { HttpClientRequest } from '../../../../src/integrations/http/types'; -import { LRUMap } from '../../../../src/utils/lru'; +import { injectTracePropagationHeaders } from '../../../src/integrations/http/inject-trace-propagation-headers'; +import type { HttpClientRequest } from '../../../src/integrations/http/types'; const DEFAULT_SENTRY_TRACE = 'aabbccdd-aabbccdd-1'; const DEFAULT_TRACEPARENT = '00-aabbccdd-aabbccdd-01'; const DEFAULT_BAGGAGE = 'sentry-trace_id=aabbccdd,sentry-sampled=true'; -vi.mock('../../../../src/utils/traceData', () => ({ - getTraceData: vi.fn(() => ({ - 'sentry-trace': DEFAULT_SENTRY_TRACE, - traceparent: DEFAULT_TRACEPARENT, - baggage: DEFAULT_BAGGAGE, - })), -})); - -vi.mock('../../../../src/currentScopes', () => ({ - getClient: vi.fn(() => ({ - getOptions: vi.fn(() => ({ - tracePropagationTargets: undefined, +vi.mock('@sentry/core', async () => { + const actual = await vi.importActual('@sentry/core'); + return { + ...actual, + getTraceData: vi.fn(() => ({ + 'sentry-trace': DEFAULT_SENTRY_TRACE, + traceparent: DEFAULT_TRACEPARENT, + baggage: DEFAULT_BAGGAGE, })), - })), -})); + getClient: vi.fn(() => ({ + getOptions: vi.fn(() => ({ + tracePropagationTargets: undefined, + })), + })), + }; +}); function makeMockRequest(existingHeaders: Record = {}): HttpClientRequest & { setHeader: ReturnType; @@ -118,7 +119,7 @@ describe('injectTracePropagationHeaders', () => { }); it('does not inject headers when URL does not match tracePropagationTargets', async () => { - const { getClient } = await import('../../../../src/currentScopes'); + const { getClient } = await import('@sentry/core'); vi.mocked(getClient).mockReturnValue({ getOptions: vi.fn(() => ({ tracePropagationTargets: [/^https:\/\/api\.example\.com(?:\/|$)/], @@ -133,7 +134,7 @@ describe('injectTracePropagationHeaders', () => { }); it('does not inject headers when getTraceData returns null', async () => { - const { getTraceData } = await import('../../../../src/utils/traceData'); + const { getTraceData } = await import('@sentry/core'); vi.mocked(getTraceData).mockReturnValueOnce(null as any); const request = makeMockRequest(); @@ -144,7 +145,7 @@ describe('injectTracePropagationHeaders', () => { }); it('does not inject headers when getClient returns undefined', async () => { - const { getClient } = await import('../../../../src/currentScopes'); + const { getClient } = await import('@sentry/core'); vi.mocked(getClient).mockReturnValueOnce(undefined); const request = makeMockRequest(); @@ -160,7 +161,7 @@ describe('injectTracePropagationHeaders', () => { it('caches propagation decisions in the decision map', async () => { // tracePropagationTargets must be defined for the decision to be cached - const { getClient } = await import('../../../../src/currentScopes'); + const { getClient } = await import('@sentry/core'); vi.mocked(getClient).mockReturnValue({ getOptions: vi.fn(() => ({ tracePropagationTargets: ['example.com'], diff --git a/packages/core/test/lib/integrations/http/server-subscription.test.ts b/packages/server-utils/test/integrations/http/server-subscription.test.ts similarity index 94% rename from packages/core/test/lib/integrations/http/server-subscription.test.ts rename to packages/server-utils/test/integrations/http/server-subscription.test.ts index 6be81c51f210..783784ea684b 100644 --- a/packages/core/test/lib/integrations/http/server-subscription.test.ts +++ b/packages/server-utils/test/integrations/http/server-subscription.test.ts @@ -2,12 +2,12 @@ import * as http from 'node:http'; import type { AddressInfo } from 'node:net'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { getIsolationScope } from '../../../../src/currentScopes'; -import { setCurrentClient } from '../../../../src/sdk'; -import { HTTP_ON_SERVER_REQUEST } from '../../../../src/integrations/http/constants'; -import { getHttpServerSubscriptions } from '../../../../src/integrations/http/server-subscription'; -import type { Event } from '../../../../src/types/event'; -import { getDefaultTestClientOptions, TestClient } from '../../../mocks/client'; +import { getIsolationScope } from '@sentry/core'; +import { setCurrentClient } from '@sentry/core'; +import { HTTP_ON_SERVER_REQUEST } from '../../../src/integrations/http/constants'; +import { getHttpServerSubscriptions } from '../../../src/integrations/http/server-subscription'; +import type { Event } from '@sentry/core'; +import { getDefaultTestClientOptions, TestClient } from '../../mocks/client'; describe('getHttpServerSubscriptions', () => { let client: TestClient; diff --git a/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts b/packages/server-utils/test/integrations/mcp-server/mcpServerErrorCapture.test.ts similarity index 91% rename from packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts rename to packages/server-utils/test/integrations/mcp-server/mcpServerErrorCapture.test.ts index 210b303b29bf..ccbe3c814fdf 100644 --- a/packages/core/test/lib/integrations/mcp-server/mcpServerErrorCapture.test.ts +++ b/packages/server-utils/test/integrations/mcp-server/mcpServerErrorCapture.test.ts @@ -1,19 +1,18 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import * as currentScopes from '../../../../src/currentScopes'; -import * as exports from '../../../../src/exports'; -import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; -import { captureError } from '../../../../src/integrations/mcp-server/errorCapture'; +import * as sentryCore from '@sentry/core'; +import { wrapMcpServerWithSentry } from '../../../src/integrations/mcp-server'; +import { captureError } from '../../../src/integrations/mcp-server/errorCapture'; import { createMockMcpServer } from './testUtils'; describe('MCP Server Error Capture', () => { - const captureExceptionSpy = vi.spyOn(exports, 'captureException'); - const getClientSpy = vi.spyOn(currentScopes, 'getClient'); + const captureExceptionSpy = vi.spyOn(sentryCore, 'captureException'); + const getClientSpy = vi.spyOn(sentryCore, 'getClient'); beforeEach(() => { vi.clearAllMocks(); getClientSpy.mockReturnValue({ getOptions: () => ({ sendDefaultPii: true }), - } as ReturnType); + } as ReturnType); }); describe('captureError', () => { diff --git a/packages/core/test/lib/integrations/mcp-server/mcpServerWrapper.test.ts b/packages/server-utils/test/integrations/mcp-server/mcpServerWrapper.test.ts similarity index 95% rename from packages/core/test/lib/integrations/mcp-server/mcpServerWrapper.test.ts rename to packages/server-utils/test/integrations/mcp-server/mcpServerWrapper.test.ts index 845d7d4786da..93cfa305041e 100644 --- a/packages/core/test/lib/integrations/mcp-server/mcpServerWrapper.test.ts +++ b/packages/server-utils/test/integrations/mcp-server/mcpServerWrapper.test.ts @@ -1,7 +1,6 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import * as currentScopes from '../../../../src/currentScopes'; -import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; -import * as tracingModule from '../../../../src/tracing'; +import * as sentryCore from '@sentry/core'; +import { wrapMcpServerWithSentry } from '../../../src/integrations/mcp-server'; import { createMockMcpServer, createMockMcpServerWithPreregisteredHandlers, @@ -9,9 +8,9 @@ import { } from './testUtils'; describe('wrapMcpServerWithSentry', () => { - const startSpanSpy = vi.spyOn(tracingModule, 'startSpan'); - const startInactiveSpanSpy = vi.spyOn(tracingModule, 'startInactiveSpan'); - const getClientSpy = vi.spyOn(currentScopes, 'getClient'); + const startSpanSpy = vi.spyOn(sentryCore, 'startSpan'); + const startInactiveSpanSpy = vi.spyOn(sentryCore, 'startInactiveSpan'); + const getClientSpy = vi.spyOn(sentryCore, 'getClient'); beforeEach(() => { vi.clearAllMocks(); diff --git a/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts b/packages/server-utils/test/integrations/mcp-server/piiFiltering.test.ts similarity index 89% rename from packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts rename to packages/server-utils/test/integrations/mcp-server/piiFiltering.test.ts index 5cfcd5cb1bfe..7bba1399c23c 100644 --- a/packages/core/test/lib/integrations/mcp-server/piiFiltering.test.ts +++ b/packages/server-utils/test/integrations/mcp-server/piiFiltering.test.ts @@ -1,13 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import * as currentScopes from '../../../../src/currentScopes'; -import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; -import { filterMcpPiiFromSpanData } from '../../../../src/integrations/mcp-server/piiFiltering'; -import * as tracingModule from '../../../../src/tracing'; +import * as sentryCore from '@sentry/core'; +import { wrapMcpServerWithSentry } from '../../../src/integrations/mcp-server'; +import { filterMcpPiiFromSpanData } from '../../../src/integrations/mcp-server/piiFiltering'; import { createMockMcpServer, createMockTransport } from './testUtils'; describe('MCP Server PII Filtering', () => { - const startInactiveSpanSpy = vi.spyOn(tracingModule, 'startInactiveSpan'); - const getClientSpy = vi.spyOn(currentScopes, 'getClient'); + const startInactiveSpanSpy = vi.spyOn(sentryCore, 'startInactiveSpan'); + const getClientSpy = vi.spyOn(sentryCore, 'getClient'); beforeEach(() => { vi.clearAllMocks(); @@ -28,7 +27,7 @@ describe('MCP Server PII Filtering', () => { getOptions: () => ({ sendDefaultPii: true }), getDsn: () => ({ publicKey: 'test-key', host: 'test-host' }), emit: vi.fn(), - } as unknown as ReturnType); + } as unknown as ReturnType); const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); await wrappedMcpServer.connect(mockTransport); @@ -64,7 +63,7 @@ describe('MCP Server PII Filtering', () => { getOptions: () => ({ sendDefaultPii: false }), getDsn: () => ({ publicKey: 'test-key', host: 'test-host' }), emit: vi.fn(), - } as unknown as ReturnType); + } as unknown as ReturnType); const wrappedMcpServer = wrapMcpServerWithSentry(mockMcpServer); await wrappedMcpServer.connect(mockTransport); diff --git a/packages/core/test/lib/integrations/mcp-server/semanticConventions.test.ts b/packages/server-utils/test/integrations/mcp-server/semanticConventions.test.ts similarity index 96% rename from packages/core/test/lib/integrations/mcp-server/semanticConventions.test.ts rename to packages/server-utils/test/integrations/mcp-server/semanticConventions.test.ts index 356cc4152123..faf51ade05a8 100644 --- a/packages/core/test/lib/integrations/mcp-server/semanticConventions.test.ts +++ b/packages/server-utils/test/integrations/mcp-server/semanticConventions.test.ts @@ -1,13 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import * as currentScopes from '../../../../src/currentScopes'; -import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; -import * as tracingModule from '../../../../src/tracing'; +import * as sentryCore from '@sentry/core'; +import { wrapMcpServerWithSentry } from '../../../src/integrations/mcp-server'; import { createMockMcpServer, createMockTransport } from './testUtils'; describe('MCP Server Semantic Conventions', () => { - const startSpanSpy = vi.spyOn(tracingModule, 'startSpan'); - const startInactiveSpanSpy = vi.spyOn(tracingModule, 'startInactiveSpan'); - const getClientSpy = vi.spyOn(currentScopes, 'getClient'); + const startSpanSpy = vi.spyOn(sentryCore, 'startSpan'); + const startInactiveSpanSpy = vi.spyOn(sentryCore, 'startInactiveSpan'); + const getClientSpy = vi.spyOn(sentryCore, 'getClient'); beforeEach(() => { vi.clearAllMocks(); @@ -16,7 +15,7 @@ describe('MCP Server Semantic Conventions', () => { getOptions: () => ({ sendDefaultPii: true }), getDsn: () => ({ publicKey: 'test-key', host: 'test-host' }), emit: vi.fn(), - } as unknown as ReturnType); + } as unknown as ReturnType); }); describe('Span Creation & Semantic Conventions', () => { @@ -372,7 +371,7 @@ describe('MCP Server Semantic Conventions', () => { end: endSpy, }; startInactiveSpanSpy.mockReturnValueOnce( - mockSpan as unknown as ReturnType, + mockSpan as unknown as ReturnType, ); const toolCallRequest = { @@ -447,7 +446,7 @@ describe('MCP Server Semantic Conventions', () => { end: endSpy, }; startInactiveSpanSpy.mockReturnValueOnce( - mockSpan as unknown as ReturnType, + mockSpan as unknown as ReturnType, ); const promptCallRequest = { @@ -515,7 +514,7 @@ describe('MCP Server Semantic Conventions', () => { const setAttributesSpy = vi.fn(); const mockSpan = { setAttributes: setAttributesSpy, setStatus: vi.fn(), end: vi.fn() }; startInactiveSpanSpy.mockReturnValueOnce( - mockSpan as unknown as ReturnType, + mockSpan as unknown as ReturnType, ); transport.onmessage?.({ jsonrpc: '2.0', method: 'tools/call', id: 'req-1', params: { name: 'tool' } }, {}); @@ -542,7 +541,7 @@ describe('MCP Server Semantic Conventions', () => { const setAttributesSpy = vi.fn(); const mockSpan = { setAttributes: setAttributesSpy, setStatus: vi.fn(), end: vi.fn() }; startInactiveSpanSpy.mockReturnValueOnce( - mockSpan as unknown as ReturnType, + mockSpan as unknown as ReturnType, ); transport.onmessage?.({ jsonrpc: '2.0', method: 'prompts/get', id: 'req-1', params: { name: 'prompt' } }, {}); diff --git a/packages/core/test/lib/integrations/mcp-server/testUtils.ts b/packages/server-utils/test/integrations/mcp-server/testUtils.ts similarity index 100% rename from packages/core/test/lib/integrations/mcp-server/testUtils.ts rename to packages/server-utils/test/integrations/mcp-server/testUtils.ts diff --git a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts b/packages/server-utils/test/integrations/mcp-server/transportInstrumentation.test.ts similarity index 98% rename from packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts rename to packages/server-utils/test/integrations/mcp-server/transportInstrumentation.test.ts index d8cc546393ec..6294b45bb3f2 100644 --- a/packages/core/test/lib/integrations/mcp-server/transportInstrumentation.test.ts +++ b/packages/server-utils/test/integrations/mcp-server/transportInstrumentation.test.ts @@ -1,12 +1,12 @@ import { beforeEach, describe, expect, it, vi } from 'vitest'; -import * as currentScopes from '../../../../src/currentScopes'; -import { wrapMcpServerWithSentry } from '../../../../src/integrations/mcp-server'; +import * as sentryCore from '@sentry/core'; +import { wrapMcpServerWithSentry } from '../../../src/integrations/mcp-server'; import { buildTransportAttributes, extractSessionDataFromInitializeRequest, extractSessionDataFromInitializeResponse, getTransportTypes, -} from '../../../../src/integrations/mcp-server/sessionExtraction'; +} from '../../../src/integrations/mcp-server/sessionExtraction'; import { cleanupSessionDataForTransport, getClientInfoForTransport, @@ -14,15 +14,14 @@ import { getSessionDataForTransport, storeSessionDataForTransport, updateSessionDataForTransport, -} from '../../../../src/integrations/mcp-server/sessionManagement'; -import { buildMcpServerSpanConfig } from '../../../../src/integrations/mcp-server/spans'; +} from '../../../src/integrations/mcp-server/sessionManagement'; +import { buildMcpServerSpanConfig } from '../../../src/integrations/mcp-server/spans'; import { wrapTransportError, wrapTransportOnClose, wrapTransportOnMessage, wrapTransportSend, -} from '../../../../src/integrations/mcp-server/transport'; -import * as tracingModule from '../../../../src/tracing'; +} from '../../../src/integrations/mcp-server/transport'; import { createMockMcpServer, createMockSseTransport, @@ -32,9 +31,9 @@ import { } from './testUtils'; describe('MCP Server Transport Instrumentation', () => { - const startSpanSpy = vi.spyOn(tracingModule, 'startSpan'); - const startInactiveSpanSpy = vi.spyOn(tracingModule, 'startInactiveSpan'); - const getClientSpy = vi.spyOn(currentScopes, 'getClient'); + const startSpanSpy = vi.spyOn(sentryCore, 'startSpan'); + const startInactiveSpanSpy = vi.spyOn(sentryCore, 'startInactiveSpan'); + const getClientSpy = vi.spyOn(sentryCore, 'getClient'); beforeEach(() => { vi.clearAllMocks(); diff --git a/packages/core/test/lib/integrations/postgresjs.test.ts b/packages/server-utils/test/integrations/postgresjs.test.ts similarity index 99% rename from packages/core/test/lib/integrations/postgresjs.test.ts rename to packages/server-utils/test/integrations/postgresjs.test.ts index dfc159808377..313375d1d243 100644 --- a/packages/core/test/lib/integrations/postgresjs.test.ts +++ b/packages/server-utils/test/integrations/postgresjs.test.ts @@ -1,6 +1,6 @@ +import * as sentryCore from '@sentry/core'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; -import { _reconstructQuery, _sanitizeSqlQuery, instrumentPostgresJsSql } from '../../../src/integrations/postgresjs'; -import * as spanUtils from '../../../src/utils/spanUtils'; +import { _reconstructQuery, _sanitizeSqlQuery, instrumentPostgresJsSql } from '../../src/integrations/postgresjs'; describe('PostgresJs portable instrumentation', () => { describe('_reconstructQuery', () => { @@ -509,7 +509,7 @@ describe('PostgresJs portable instrumentation', () => { describe('span creation', () => { beforeEach(() => { // By default, mock getActiveSpan to return undefined (no parent) - vi.spyOn(spanUtils, 'getActiveSpan').mockReturnValue(undefined); + vi.spyOn(sentryCore, 'getActiveSpan').mockReturnValue(undefined); }); afterEach(() => { diff --git a/packages/server-utils/test/mocks/client.ts b/packages/server-utils/test/mocks/client.ts new file mode 100644 index 000000000000..4842eacb470b --- /dev/null +++ b/packages/server-utils/test/mocks/client.ts @@ -0,0 +1,101 @@ +import { + Client, + type ClientOptions, + createTransport, + type Event, + type EventHint, + initAndBind, + type Integration, + type Outcome, + type ParameterizedString, + resolvedSyncPromise, + type Session, + type SeverityLevel, +} from '@sentry/core'; + +export function getDefaultTestClientOptions(options: Partial = {}): TestClientOptions { + return { + integrations: [], + sendClientReports: true, + transport: () => + createTransport( + { + recordDroppedEvent: () => undefined, + }, // noop + _ => resolvedSyncPromise({}), + ), + stackParser: () => [], + ...options, + }; +} + +export interface TestClientOptions extends ClientOptions { + test?: boolean; + mockInstallFailure?: boolean; + enableSend?: boolean; + defaultIntegrations?: Integration[] | false; +} + +export class TestClient extends Client { + public static instance?: TestClient; + public static sendEventCalled?: (event: Event) => void; + + public event?: Event; + public session?: Session; + + public constructor(options: TestClientOptions) { + super(options); + TestClient.instance = this; + } + + public eventFromException(exception: any): PromiseLike { + const event: Event = { + exception: { + values: [ + { + type: exception.name, + value: exception.message, + }, + ], + }, + }; + + const frames = this._options.stackParser(exception.stack || '', 1); + if (frames.length && event.exception?.values?.[0]) { + event.exception.values[0] = { ...event.exception.values[0], stacktrace: { frames } }; + } + + return resolvedSyncPromise(event); + } + + public eventFromMessage(message: ParameterizedString, level: SeverityLevel = 'info'): PromiseLike { + return resolvedSyncPromise({ message, level }); + } + + public sendEvent(event: Event, hint?: EventHint): void { + this.event = event; + + if (this._options.enableSend) { + super.sendEvent(event, hint); + return; + } + + // In real life, this will get deleted as part of envelope creation. + delete event.sdkProcessingMetadata; + + TestClient.sendEventCalled?.(event); + } + + public sendSession(session: Session): void { + this.session = session; + } + + // Public proxy for protected method + public _clearOutcomes(): Outcome[] { + return super._clearOutcomes(); + } +} + +export function init(options: TestClientOptions): void { + initAndBind(TestClient, options); +} diff --git a/packages/core/test/lib/server-runtime-client.test.ts b/packages/server-utils/test/server-runtime-client.test.ts similarity index 96% rename from packages/core/test/lib/server-runtime-client.test.ts rename to packages/server-utils/test/server-runtime-client.test.ts index 12ae4d625503..fa40ac9c6a66 100644 --- a/packages/core/test/lib/server-runtime-client.test.ts +++ b/packages/server-utils/test/server-runtime-client.test.ts @@ -1,9 +1,16 @@ +import { + _INTERNAL_captureMetric, + _INTERNAL_getMetricBuffer, + applySdkMetadata, + createTransport, + type Event, + type EventHint, + Scope, + SDK_VERSION, +} from '@sentry/core'; import { describe, expect, it, test, vi } from 'vitest'; -import { applySdkMetadata, createTransport, Scope } from '../../src'; -import { _INTERNAL_captureMetric, _INTERNAL_getMetricBuffer } from '../../src/metrics/internal'; -import type { ServerRuntimeClientOptions } from '../../src/server-runtime-client'; -import { ServerRuntimeClient } from '../../src/server-runtime-client'; -import type { Event, EventHint } from '../../src/types/event'; +import type { ServerRuntimeClientOptions } from '../src/server-runtime-client'; +import { ServerRuntimeClient } from '../src/server-runtime-client'; const PUBLIC_DSN = 'https://username@domain/123'; @@ -217,7 +224,7 @@ describe('ServerRuntimeClient', () => { client = new ServerRuntimeClient(options); expect(client.getOptions().transportOptions?.headers).toEqual({ - 'user-agent': 'sentry.javascript.core/0.0.0-unknown.0', + 'user-agent': `sentry.javascript.core/${SDK_VERSION}`, }); }); diff --git a/packages/core/test/lib/trpc.test.ts b/packages/server-utils/test/trpc.test.ts similarity index 72% rename from packages/core/test/lib/trpc.test.ts rename to packages/server-utils/test/trpc.test.ts index 587d531b5d00..a6f4ae79164a 100644 --- a/packages/core/test/lib/trpc.test.ts +++ b/packages/server-utils/test/trpc.test.ts @@ -1,10 +1,8 @@ +import * as sentryCore from '@sentry/core'; +import { type Client, setCurrentClient, type Span } from '@sentry/core'; import { beforeEach, describe, expect, test, vi } from 'vitest'; -import { type Client, setCurrentClient, type Span, trpcMiddleware } from '../../src'; -import * as currentScopes from '../../src/currentScopes'; -import * as exports from '../../src/exports'; -import * as tracing from '../../src/tracing'; -import { resolveDataCollectionOptions } from '../../src/utils/data-collection/resolveDataCollectionOptions'; -import { getDefaultTestClientOptions, TestClient } from '../mocks/client'; +import { trpcMiddleware } from '../src/trpc'; +import { getDefaultTestClientOptions, TestClient } from './mocks/client'; describe('trpcMiddleware', () => { let client: Client; @@ -14,7 +12,8 @@ describe('trpcMiddleware', () => { normalizeDepth: 3, sendDefaultPii: false, }), - getDataCollectionOptions: vi.fn().mockReturnValue(resolveDataCollectionOptions({ sendDefaultPii: false })), + // trpc.ts only reads `httpBodies`; a minimal mock is enough here. + getDataCollectionOptions: vi.fn().mockReturnValue({ httpBodies: [] }), captureException: vi.fn(), } as unknown as Client; @@ -38,10 +37,10 @@ describe('trpcMiddleware', () => { client = new TestClient(options); setCurrentClient(client); client.init(); - vi.spyOn(currentScopes, 'getClient').mockReturnValue(mockClient); - vi.spyOn(tracing, 'startSpanManual').mockImplementation((name, callback) => callback(mockSpan, () => {})); - vi.spyOn(currentScopes, 'withIsolationScope').mockImplementation(withIsolationScope); - vi.spyOn(exports, 'captureException').mockImplementation(() => 'mock-event-id'); + vi.spyOn(sentryCore, 'getClient').mockReturnValue(mockClient); + vi.spyOn(sentryCore, 'startSpanManual').mockImplementation((_name, callback) => callback(mockSpan, () => {})); + vi.spyOn(sentryCore, 'withIsolationScope').mockImplementation(withIsolationScope); + vi.spyOn(sentryCore, 'captureException').mockImplementation(() => 'mock-event-id'); }); test('creates span with correct attributes', async () => { @@ -54,7 +53,7 @@ describe('trpcMiddleware', () => { next, }); - expect(tracing.startSpanManual).toHaveBeenCalledWith( + expect(sentryCore.startSpanManual).toHaveBeenCalledWith( { name: 'trpc/test.procedure', op: 'rpc.server', @@ -79,7 +78,7 @@ describe('trpcMiddleware', () => { next, }); - expect(exports.captureException).toHaveBeenCalledWith(error, { + expect(sentryCore.captureException).toHaveBeenCalledWith(error, { mechanism: { handled: false, type: 'auto.rpc.trpc.middleware' }, }); }); @@ -116,7 +115,7 @@ describe('trpcMiddleware', () => { }), ).rejects.toThrow(error); - expect(exports.captureException).toHaveBeenCalledWith(error, { + expect(sentryCore.captureException).toHaveBeenCalledWith(error, { mechanism: { handled: false, type: 'auto.rpc.trpc.middleware' }, }); }); @@ -131,7 +130,7 @@ describe('trpcMiddleware', () => { next, }); - expect(tracing.startSpanManual).toHaveBeenCalledWith( + expect(sentryCore.startSpanManual).toHaveBeenCalledWith( expect.objectContaining({ forceTransaction: true, }), diff --git a/packages/solidstart/src/server/withServerActionInstrumentation.ts b/packages/solidstart/src/server/withServerActionInstrumentation.ts index bcd9389a6bf4..8521e2563a8e 100644 --- a/packages/solidstart/src/server/withServerActionInstrumentation.ts +++ b/packages/solidstart/src/server/withServerActionInstrumentation.ts @@ -1,9 +1,9 @@ import { - flushIfServerless, handleCallbackErrors, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SPAN_STATUS_ERROR, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { captureException, getActiveSpan, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, spanToJSON, startSpan } from '@sentry/node'; import { isRedirect } from './utils'; diff --git a/packages/sveltekit/src/server-common/handle.ts b/packages/sveltekit/src/server-common/handle.ts index c0e33c49c031..172e1b3d10a1 100644 --- a/packages/sveltekit/src/server-common/handle.ts +++ b/packages/sveltekit/src/server-common/handle.ts @@ -2,7 +2,6 @@ import type { Span } from '@sentry/core'; import { continueTrace, debug, - flushIfServerless, getClient, getCurrentScope, getDefaultIsolationScope, @@ -20,6 +19,7 @@ import { winterCGRequestToRequestData, withIsolationScope, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { Handle, ResolveOptions } from '@sveltejs/kit'; import { DEBUG_BUILD } from '../common/debug-build'; import { getTracePropagationData, sendErrorToSentry } from './utils'; diff --git a/packages/sveltekit/src/server-common/handleError.ts b/packages/sveltekit/src/server-common/handleError.ts index 4a7bce331622..3668bf15e51b 100644 --- a/packages/sveltekit/src/server-common/handleError.ts +++ b/packages/sveltekit/src/server-common/handleError.ts @@ -1,4 +1,5 @@ -import { captureException, consoleSandbox, flushIfServerless } from '@sentry/core'; +import { captureException, consoleSandbox } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { HandleServerError } from '@sveltejs/kit'; // The SvelteKit default error handler just logs the error's stack trace to the console diff --git a/packages/sveltekit/src/server-common/load.ts b/packages/sveltekit/src/server-common/load.ts index 9cad4d4e98ae..8a7d52c26b14 100644 --- a/packages/sveltekit/src/server-common/load.ts +++ b/packages/sveltekit/src/server-common/load.ts @@ -1,10 +1,10 @@ import { addNonEnumerableProperty, - flushIfServerless, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { LoadEvent, ServerLoadEvent } from '@sveltejs/kit'; import type { SentryWrappedFlag } from '../common/utils'; import { getRouteId } from '../common/utils'; diff --git a/packages/sveltekit/src/server-common/serverRoute.ts b/packages/sveltekit/src/server-common/serverRoute.ts index 3b98ce270f2d..b9f387d9264a 100644 --- a/packages/sveltekit/src/server-common/serverRoute.ts +++ b/packages/sveltekit/src/server-common/serverRoute.ts @@ -1,10 +1,10 @@ import { addNonEnumerableProperty, - flushIfServerless, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, startSpan, } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import type { RequestEvent } from '@sveltejs/kit'; import { sendErrorToSentry } from './utils'; diff --git a/packages/tanstackstart-react/src/server/wrapFetchWithSentry.ts b/packages/tanstackstart-react/src/server/wrapFetchWithSentry.ts index fab2788cd234..70e32d7e1f04 100644 --- a/packages/tanstackstart-react/src/server/wrapFetchWithSentry.ts +++ b/packages/tanstackstart-react/src/server/wrapFetchWithSentry.ts @@ -1,4 +1,5 @@ -import { flushIfServerless, getTraceMetaTags } from '@sentry/core'; +import { getTraceMetaTags } from '@sentry/core'; +import { flushIfServerless } from '@sentry-internal/server-utils'; import { captureException, SEMANTIC_ATTRIBUTE_SENTRY_OP, diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index 7d8b0b833cfa..90f6761f6544 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -41,6 +41,7 @@ "dependencies": { "@opentelemetry/api": "^1.9.1", "@opentelemetry/resources": "^2.6.1", + "@sentry-internal/server-utils": "10.54.0", "@sentry/core": "10.54.0" }, "devDependencies": { diff --git a/packages/vercel-edge/src/client.ts b/packages/vercel-edge/src/client.ts index d72f5f2f6718..6dbdacabb4ea 100644 --- a/packages/vercel-edge/src/client.ts +++ b/packages/vercel-edge/src/client.ts @@ -1,6 +1,7 @@ import type { BasicTracerProvider } from '@opentelemetry/sdk-trace-base'; -import type { ServerRuntimeClientOptions } from '@sentry/core'; -import { applySdkMetadata, ServerRuntimeClient } from '@sentry/core'; +import type { ServerRuntimeClientOptions } from '@sentry-internal/server-utils'; +import { applySdkMetadata } from '@sentry/core'; +import { ServerRuntimeClient } from '@sentry-internal/server-utils'; import type { VercelEdgeClientOptions } from './types'; declare const process: { diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts index 655ade4e18ad..48eefa1ab75d 100644 --- a/packages/vercel-edge/src/index.ts +++ b/packages/vercel-edge/src/index.ts @@ -90,11 +90,9 @@ export { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, - trpcMiddleware, spanToJSON, spanToTraceHeader, spanToBaggageHeader, - wrapMcpServerWithSentry, consoleLoggingIntegration, createConsolaReporter, createLangChainCallbackHandler, @@ -105,6 +103,10 @@ export { withStreamedSpan, spanStreamingIntegration, } from '@sentry/core'; +export { + trpcMiddleware, + wrapMcpServerWithSentry, +} from '@sentry-internal/server-utils'; export { VercelEdgeClient } from './client'; export { getDefaultIntegrations, init } from './sdk'; diff --git a/packages/vercel-edge/src/sdk.ts b/packages/vercel-edge/src/sdk.ts index d0666a6f66e1..4819dd89b64b 100644 --- a/packages/vercel-edge/src/sdk.ts +++ b/packages/vercel-edge/src/sdk.ts @@ -14,11 +14,13 @@ import { hasSpansEnabled, inboundFiltersIntegration, linkedErrorsIntegration, - nodeStackLineParser, requestDataIntegration, spanStreamingIntegration, stackParserFromStackParserOptions, } from '@sentry/core'; +import { + nodeStackLineParser, +} from '@sentry-internal/server-utils'; import { enhanceDscWithOpenTelemetryRootSpanName, getSentryResource,