diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts index fb3d45c5c188..02df8c4158fb 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/layer.test.ts @@ -45,7 +45,7 @@ test.describe('Lambda layer', () => { expect.objectContaining({ data: expect.objectContaining({ 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', url: 'http://example.com/', }), description: 'GET http://example.com/', @@ -113,7 +113,7 @@ test.describe('Lambda layer', () => { expect.objectContaining({ data: expect.objectContaining({ 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', url: 'http://example.com/', }), description: 'GET http://example.com/', diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts index 943d5a2ab0f3..3f07fdd9b696 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts +++ b/dev-packages/e2e-tests/test-applications/aws-serverless/tests/npm.test.ts @@ -45,7 +45,7 @@ test.describe('NPM package', () => { expect.objectContaining({ data: expect.objectContaining({ 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', url: 'http://example.com/', }), description: 'GET http://example.com/', @@ -113,7 +113,7 @@ test.describe('NPM package', () => { expect.objectContaining({ data: expect.objectContaining({ 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', url: 'http://example.com/', }), description: 'GET http://example.com/', diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/tests/request-instrumentation.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-14/tests/request-instrumentation.test.ts index 2446ffa68659..66752e7c2e41 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/tests/request-instrumentation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/tests/request-instrumentation.test.ts @@ -28,7 +28,7 @@ test('Should send a transaction with a fetch span', async ({ page }) => { data: expect.objectContaining({ 'http.method': 'GET', 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', }), description: 'GET https://github.com/', }), diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/request-instrumentation.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/request-instrumentation.test.ts index f392a63d4086..939347da2a09 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/request-instrumentation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tests/request-instrumentation.test.ts @@ -16,7 +16,7 @@ test.skip('Should send a transaction with a http span', async ({ request }) => { data: expect.objectContaining({ 'http.method': 'GET', 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', }), description: 'GET https://example.com/', }), diff --git a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/request-instrumentation.test.ts b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/request-instrumentation.test.ts index c65ba88c39c3..65a6820a83da 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/request-instrumentation.test.ts +++ b/dev-packages/e2e-tests/test-applications/nextjs-pages-dir/tests/request-instrumentation.test.ts @@ -16,7 +16,7 @@ test.skip('Should send a transaction with a http span', async ({ request }) => { data: expect.objectContaining({ 'http.method': 'GET', 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', }), description: 'GET https://example.com/', }), diff --git a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/tests/server.test.ts b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/tests/server.test.ts index 937f2b7acc27..7e1b95e9e53f 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-esm-preload/tests/server.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-express-esm-preload/tests/server.test.ts @@ -133,7 +133,7 @@ test('Should record spans from http instrumentation', async ({ request }) => { trace_id: expect.stringMatching(/[a-f0-9]{32}/), data: expect.objectContaining({ 'http.flavor': '1.1', - 'http.host': 'example.com:80', + 'http.host': 'example.com', 'http.method': 'GET', 'http.response.status_code': 200, 'http.status_code': 200, @@ -146,7 +146,7 @@ test('Should record spans from http instrumentation', async ({ request }) => { 'net.transport': 'ip_tcp', 'otel.kind': 'CLIENT', 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', url: 'http://example.com/', }), description: 'GET http://example.com/', @@ -155,6 +155,6 @@ test('Should record spans from http instrumentation', async ({ request }) => { timestamp: expect.any(Number), status: 'ok', op: 'http.client', - origin: 'auto.http.otel.http', + origin: 'auto.http.client', }); }); diff --git a/dev-packages/e2e-tests/test-applications/react-router-6/tsconfig.json b/dev-packages/e2e-tests/test-applications/react-router-6/tsconfig.json index 4cc95dc2689a..74afe717c988 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-6/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/react-router-6/tsconfig.json @@ -10,7 +10,7 @@ "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, diff --git a/dev-packages/e2e-tests/test-applications/react-send-to-sentry/tsconfig.json b/dev-packages/e2e-tests/test-applications/react-send-to-sentry/tsconfig.json index 4cc95dc2689a..74afe717c988 100644 --- a/dev-packages/e2e-tests/test-applications/react-send-to-sentry/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/react-send-to-sentry/tsconfig.json @@ -10,7 +10,7 @@ "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", - "moduleResolution": "node", + "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, diff --git a/dev-packages/node-core-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts b/dev-packages/node-core-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts index 17393f21a8a4..a1a9ce5d51dc 100644 --- a/dev-packages/node-core-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts +++ b/dev-packages/node-core-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts @@ -1,202 +1,101 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; -import { conditionalTest } from '../../../../utils'; import { createEsmAndCjsTests } from '../../../../utils/runner'; describe('outgoing http requests with tracing & spans disabled', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { - conditionalTest({ min: 22 })('node >=22', () => { - test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => { - expect.assertions(11); + test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => { + expect.assertions(11); - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); - expect(headers['baggage']).toEqual(expect.any(String)); - }) - .get('/api/v1', headers => { - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); - expect(headers['baggage']).toEqual(expect.any(String)); - }) - .get('/api/v2', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v3', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .start(); + const [SERVER_URL, closeTestServer] = await createTestServer() + .get('/api/v0', headers => { + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); + expect(headers['baggage']).toEqual(expect.any(String)); + }) + .get('/api/v1', headers => { + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); + expect(headers['baggage']).toEqual(expect.any(String)); + }) + .get('/api/v2', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .get('/api/v3', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .start(); - await createRunner() - .withEnv({ SERVER_URL }) - .expect({ - event: { - exception: { - values: [ - { - type: 'Error', - value: 'foo', - }, - ], - }, - breadcrumbs: [ - { - message: 'manual breadcrumb', - timestamp: expect.any(Number), - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v0`, - status_code: 200, - ADDED_PATH: '/api/v0', - }, - timestamp: expect.any(Number), - type: 'http', - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v1`, - status_code: 200, - ADDED_PATH: '/api/v1', - }, - timestamp: expect.any(Number), - type: 'http', - }, + await createRunner() + .withEnv({ SERVER_URL }) + .expect({ + event: { + exception: { + values: [ { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v2`, - status_code: 200, - ADDED_PATH: '/api/v2', - }, - timestamp: expect.any(Number), - type: 'http', - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v3`, - status_code: 200, - ADDED_PATH: '/api/v3', - }, - timestamp: expect.any(Number), - type: 'http', + type: 'Error', + value: 'foo', }, ], }, - }) - .start() - .completed(); - - closeTestServer(); - }); - }); - - // On older node versions, outgoing requests do not get trace-headers injected, sadly - // This is because the necessary diagnostics channel hook is not available yet - conditionalTest({ max: 21 })('node <22', () => { - test('outgoing http requests generate breadcrumbs correctly with tracing & spans disabled', async () => { - expect.assertions(9); - - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - // This is not instrumented, sadly - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v1', headers => { - // This is not instrumented, sadly - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v2', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v3', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .start(); - - await createRunner() - .withEnv({ SERVER_URL }) - .expect({ - event: { - exception: { - values: [ - { - type: 'Error', - value: 'foo', - }, - ], + breadcrumbs: [ + { + message: 'manual breadcrumb', + timestamp: expect.any(Number), }, - breadcrumbs: [ - { - message: 'manual breadcrumb', - timestamp: expect.any(Number), - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v0`, - status_code: 200, - ADDED_PATH: '/api/v0', - }, - timestamp: expect.any(Number), - type: 'http', + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v0`, + status_code: 200, + ADDED_PATH: '/api/v0', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v1`, - status_code: 200, - ADDED_PATH: '/api/v1', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v1`, + status_code: 200, + ADDED_PATH: '/api/v1', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v2`, - status_code: 200, - ADDED_PATH: '/api/v2', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v2`, + status_code: 200, + ADDED_PATH: '/api/v2', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v3`, - status_code: 200, - ADDED_PATH: '/api/v3', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v3`, + status_code: 200, + ADDED_PATH: '/api/v3', }, - ], - }, - }) - .start() - .completed(); + timestamp: expect.any(Number), + type: 'http', + }, + ], + }, + }) + .start() + .completed(); - closeTestServer(); - }); + closeTestServer(); }); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts index 0549d7e914c0..1fea661d33e5 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-basic/test.ts @@ -29,13 +29,13 @@ test('captures spans for outgoing http requests', async () => { expect.objectContaining({ description: expect.stringMatching(/GET .*\/api\/v0/), op: 'http.client', - origin: 'auto.http.otel.http', + origin: 'auto.http.client', status: 'ok', }), expect.objectContaining({ description: expect.stringMatching(/GET .*\/api\/v1/), op: 'http.client', - origin: 'auto.http.otel.http', + origin: 'auto.http.client', status: 'not_found', data: expect.objectContaining({ 'http.response.status_code': 404, diff --git a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts index 94ccd6c9702a..60add149deab 100644 --- a/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/http-client-spans/http-strip-query/test.ts @@ -37,11 +37,11 @@ test('strips and handles query params in spans of outgoing http requests', async 'net.transport': 'ip_tcp', 'otel.kind': 'CLIENT', 'sentry.op': 'http.client', - 'sentry.origin': 'auto.http.otel.http', + 'sentry.origin': 'auto.http.client', }, description: `GET ${SERVER_URL}/api/v0/users`, op: 'http.client', - origin: 'auto.http.otel.http', + origin: 'auto.http.client', status: 'ok', parent_span_id: txn.contexts?.trace?.span_id, span_id: expect.stringMatching(/[a-f\d]{16}/), diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts index 17393f21a8a4..a1a9ce5d51dc 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-no-tracing-no-spans/test.ts @@ -1,202 +1,101 @@ import { createTestServer } from '@sentry-internal/test-utils'; import { describe, expect } from 'vitest'; -import { conditionalTest } from '../../../../utils'; import { createEsmAndCjsTests } from '../../../../utils/runner'; describe('outgoing http requests with tracing & spans disabled', () => { createEsmAndCjsTests(__dirname, 'scenario.mjs', 'instrument.mjs', (createRunner, test) => { - conditionalTest({ min: 22 })('node >=22', () => { - test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => { - expect.assertions(11); + test('outgoing http requests are correctly instrumented with tracing & spans disabled', async () => { + expect.assertions(11); - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); - expect(headers['baggage']).toEqual(expect.any(String)); - }) - .get('/api/v1', headers => { - expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); - expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); - expect(headers['baggage']).toEqual(expect.any(String)); - }) - .get('/api/v2', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v3', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .start(); + const [SERVER_URL, closeTestServer] = await createTestServer() + .get('/api/v0', headers => { + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); + expect(headers['baggage']).toEqual(expect.any(String)); + }) + .get('/api/v1', headers => { + expect(headers['sentry-trace']).toEqual(expect.stringMatching(/^([a-f\d]{32})-([a-f\d]{16})$/)); + expect(headers['sentry-trace']).not.toEqual('00000000000000000000000000000000-0000000000000000'); + expect(headers['baggage']).toEqual(expect.any(String)); + }) + .get('/api/v2', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .get('/api/v3', headers => { + expect(headers['baggage']).toBeUndefined(); + expect(headers['sentry-trace']).toBeUndefined(); + }) + .start(); - await createRunner() - .withEnv({ SERVER_URL }) - .expect({ - event: { - exception: { - values: [ - { - type: 'Error', - value: 'foo', - }, - ], - }, - breadcrumbs: [ - { - message: 'manual breadcrumb', - timestamp: expect.any(Number), - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v0`, - status_code: 200, - ADDED_PATH: '/api/v0', - }, - timestamp: expect.any(Number), - type: 'http', - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v1`, - status_code: 200, - ADDED_PATH: '/api/v1', - }, - timestamp: expect.any(Number), - type: 'http', - }, + await createRunner() + .withEnv({ SERVER_URL }) + .expect({ + event: { + exception: { + values: [ { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v2`, - status_code: 200, - ADDED_PATH: '/api/v2', - }, - timestamp: expect.any(Number), - type: 'http', - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v3`, - status_code: 200, - ADDED_PATH: '/api/v3', - }, - timestamp: expect.any(Number), - type: 'http', + type: 'Error', + value: 'foo', }, ], }, - }) - .start() - .completed(); - - closeTestServer(); - }); - }); - - // On older node versions, outgoing requests do not get trace-headers injected, sadly - // This is because the necessary diagnostics channel hook is not available yet - conditionalTest({ max: 21 })('node <22', () => { - test('outgoing http requests generate breadcrumbs correctly with tracing & spans disabled', async () => { - expect.assertions(9); - - const [SERVER_URL, closeTestServer] = await createTestServer() - .get('/api/v0', headers => { - // This is not instrumented, sadly - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v1', headers => { - // This is not instrumented, sadly - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v2', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .get('/api/v3', headers => { - expect(headers['baggage']).toBeUndefined(); - expect(headers['sentry-trace']).toBeUndefined(); - }) - .start(); - - await createRunner() - .withEnv({ SERVER_URL }) - .expect({ - event: { - exception: { - values: [ - { - type: 'Error', - value: 'foo', - }, - ], + breadcrumbs: [ + { + message: 'manual breadcrumb', + timestamp: expect.any(Number), }, - breadcrumbs: [ - { - message: 'manual breadcrumb', - timestamp: expect.any(Number), - }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v0`, - status_code: 200, - ADDED_PATH: '/api/v0', - }, - timestamp: expect.any(Number), - type: 'http', + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v0`, + status_code: 200, + ADDED_PATH: '/api/v0', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v1`, - status_code: 200, - ADDED_PATH: '/api/v1', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v1`, + status_code: 200, + ADDED_PATH: '/api/v1', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v2`, - status_code: 200, - ADDED_PATH: '/api/v2', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v2`, + status_code: 200, + ADDED_PATH: '/api/v2', }, - { - category: 'http', - data: { - 'http.method': 'GET', - url: `${SERVER_URL}/api/v3`, - status_code: 200, - ADDED_PATH: '/api/v3', - }, - timestamp: expect.any(Number), - type: 'http', + timestamp: expect.any(Number), + type: 'http', + }, + { + category: 'http', + data: { + 'http.method': 'GET', + url: `${SERVER_URL}/api/v3`, + status_code: 200, + ADDED_PATH: '/api/v3', }, - ], - }, - }) - .start() - .completed(); + timestamp: expect.any(Number), + type: 'http', + }, + ], + }, + }) + .start() + .completed(); - closeTestServer(); - }); + closeTestServer(); }); }); }); diff --git a/dev-packages/rollup-utils/npmHelpers.mjs b/dev-packages/rollup-utils/npmHelpers.mjs index 6f399c1c3f59..e361b00ef2b8 100644 --- a/dev-packages/rollup-utils/npmHelpers.mjs +++ b/dev-packages/rollup-utils/npmHelpers.mjs @@ -21,7 +21,7 @@ import { makeSucrasePlugin, } from './plugins/index.mjs'; import { makePackageNodeEsm } from './plugins/make-esm-plugin.mjs'; -import { mergePlugins } from './utils.mjs'; +import { mergeExternals, mergePlugins } from './utils.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -47,6 +47,13 @@ export function makeBaseNPMConfig(options = {}) { excludeIframe: undefined, }); + const deps = [ + ...builtinModules.filter(m => !bundledBuiltins.includes(m)), + ...Object.keys(packageDotJSON.dependencies || {}), + ...Object.keys(packageDotJSON.peerDependencies || {}), + ...Object.keys(packageDotJSON.optionalDependencies || {}), + ]; + const defaultBaseConfig = { input: entrypoints, @@ -100,17 +107,20 @@ export function makeBaseNPMConfig(options = {}) { plugins: [nodeResolvePlugin, sucrasePlugin, debugBuildStatementReplacePlugin, rrwebBuildPlugin, cleanupPlugin], // don't include imported modules from outside the package in the final output - external: [ - ...builtinModules.filter(m => !bundledBuiltins.includes(m)), - ...Object.keys(packageDotJSON.dependencies || {}), - ...Object.keys(packageDotJSON.peerDependencies || {}), - ...Object.keys(packageDotJSON.optionalDependencies || {}), - ], + // also treat subpath exports (e.g. `@sentry/core/browser`) as external + external: id => { + // treat subpath exports as external if the package is external + return deps.some(dep => id === dep || id.startsWith(`${dep}/`)); + }, }; return deepMerge(defaultBaseConfig, packageSpecificConfig, { // Plugins have to be in the correct order or everything breaks, so when merging we have to manually re-order them - customMerge: key => (key === 'plugins' ? mergePlugins : undefined), + customMerge: key => { + if (key === 'plugins') return mergePlugins; + if (key === 'external') return mergeExternals; + return undefined; + }, }); } diff --git a/dev-packages/rollup-utils/utils.mjs b/dev-packages/rollup-utils/utils.mjs index b687ff9993c4..ea4ae8fdb1d0 100644 --- a/dev-packages/rollup-utils/utils.mjs +++ b/dev-packages/rollup-utils/utils.mjs @@ -10,6 +10,25 @@ export const insertAt = (arr, index, ...insertees) => { return newArr; }; +/** + * Turn a list of module IDs into a test function + * Includes submodule exports by checking that it starts with the name + * plus a / character. The list would contain something like `'@sentry/core'` + * and we might test it against a module id like `'@sentry/core/browser'` + */ +function toFilterFunction(list) { + return Array.isArray(list) ? id => list.some(test => id === test || id.startsWith(`${test}/`)) : list; +} + +/** + * Merge two external configs (function or array), returning a function that handles both. + */ +export function mergeExternals(base, specific) { + const baseFn = toFilterFunction(base); + const specificFn = toFilterFunction(specific); + return id => baseFn(id) || specificFn(id); +} + /** * Merge two arrays of plugins, making sure they're sorted in the correct order. */ diff --git a/packages/astro/tsconfig.json b/packages/astro/tsconfig.json index bf45a09f2d71..0b788fab5eae 100644 --- a/packages/astro/tsconfig.json +++ b/packages/astro/tsconfig.json @@ -4,6 +4,8 @@ "include": ["src/**/*"], "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" // package-specific options } } diff --git a/packages/browser/src/client.ts b/packages/browser/src/client.ts index 4ffc85b07762..8d0242d82cbf 100644 --- a/packages/browser/src/client.ts +++ b/packages/browser/src/client.ts @@ -8,7 +8,7 @@ import type { ParameterizedString, Scope, SeverityLevel, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { _INTERNAL_flushLogsBuffer, _INTERNAL_flushMetricsBuffer, @@ -16,7 +16,7 @@ import { applySdkMetadata, Client, getSDKSource, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { eventFromException, eventFromMessage } from './eventbuilder'; import { WINDOW } from './helpers'; import type { BrowserTransportOptions } from './transports/types'; diff --git a/packages/browser/src/diagnose-sdk.ts b/packages/browser/src/diagnose-sdk.ts index 0a5fdd0da05b..0be386ce6d32 100644 --- a/packages/browser/src/diagnose-sdk.ts +++ b/packages/browser/src/diagnose-sdk.ts @@ -1,4 +1,4 @@ -import { getClient, suppressTracing } from '@sentry/core'; +import { getClient, suppressTracing } from '@sentry/core/browser'; /** * A function to diagnose why the SDK might not be successfully sending data. diff --git a/packages/browser/src/eventbuilder.ts b/packages/browser/src/eventbuilder.ts index b430007b552d..76e38ec00468 100644 --- a/packages/browser/src/eventbuilder.ts +++ b/packages/browser/src/eventbuilder.ts @@ -6,7 +6,7 @@ import type { SeverityLevel, StackFrame, StackParser, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { _INTERNAL_enhanceErrorWithSentryInfo, addExceptionMechanism, @@ -22,7 +22,7 @@ import { isPlainObject, normalizeToSize, resolvedSyncPromise, -} from '@sentry/core'; +} from '@sentry/core/browser'; type Prototype = { constructor: (...args: unknown[]) => unknown }; diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index 322cc0b3c8db..0ede8e8d76be 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -20,7 +20,7 @@ export type { ExclusiveEventHintOrCaptureContext, Log, LogSeverityLevel, -} from '@sentry/core'; +} from '@sentry/core/browser'; export type { BrowserOptions } from './client'; @@ -72,14 +72,14 @@ export { updateSpanName, withStreamedSpan, metrics, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { WINDOW } from './helpers'; export { BrowserClient } from './client'; diff --git a/packages/browser/src/feedbackAsync.ts b/packages/browser/src/feedbackAsync.ts index c40964bb5c27..30f31bec01d5 100644 --- a/packages/browser/src/feedbackAsync.ts +++ b/packages/browser/src/feedbackAsync.ts @@ -5,6 +5,6 @@ import { lazyLoadIntegration } from './utils/lazyLoadIntegration'; * An integration to add user feedback to your application, * while loading most of the code lazily only when it's needed. */ -export const feedbackAsyncIntegration = buildFeedbackIntegration({ +export const feedbackAsyncIntegration: ReturnType = buildFeedbackIntegration({ lazyLoadIntegration, }); diff --git a/packages/browser/src/feedbackSync.ts b/packages/browser/src/feedbackSync.ts index ede41fefb221..879d3a7a453c 100644 --- a/packages/browser/src/feedbackSync.ts +++ b/packages/browser/src/feedbackSync.ts @@ -5,7 +5,7 @@ import { } from '@sentry-internal/feedback'; /** Add a widget to capture user feedback to your application. */ -export const feedbackSyncIntegration = buildFeedbackIntegration({ +export const feedbackSyncIntegration: ReturnType = buildFeedbackIntegration({ getModalIntegration: () => feedbackModalIntegration, getScreenshotIntegration: () => feedbackScreenshotIntegration, }); diff --git a/packages/browser/src/helpers.ts b/packages/browser/src/helpers.ts index 93c87e1d6161..09359b122450 100644 --- a/packages/browser/src/helpers.ts +++ b/packages/browser/src/helpers.ts @@ -1,4 +1,4 @@ -import type { Mechanism, WrappedFunction } from '@sentry/core'; +import type { Mechanism, WrappedFunction } from '@sentry/core/browser'; import { addExceptionMechanism, addExceptionTypeValue, @@ -9,7 +9,7 @@ import { GLOBAL_OBJ, markFunctionWrapped, withScope, -} from '@sentry/core'; +} from '@sentry/core/browser'; export const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; diff --git a/packages/browser/src/index.bundle.logs.metrics.ts b/packages/browser/src/index.bundle.logs.metrics.ts index 415a56cf7cc6..5a101f8066f8 100644 --- a/packages/browser/src/index.bundle.logs.metrics.ts +++ b/packages/browser/src/index.bundle.logs.metrics.ts @@ -8,7 +8,7 @@ import { export * from './index.bundle.base'; // TODO(v11): Export metrics here once we remove it from the base bundle. -export { logger, consoleLoggingIntegration } from '@sentry/core'; +export { logger, consoleLoggingIntegration } from '@sentry/core/browser'; export { elementTimingIntegration } from '@sentry-internal/browser-utils'; diff --git a/packages/browser/src/index.bundle.replay.logs.metrics.ts b/packages/browser/src/index.bundle.replay.logs.metrics.ts index 02938d0d7063..4a3003a491bb 100644 --- a/packages/browser/src/index.bundle.replay.logs.metrics.ts +++ b/packages/browser/src/index.bundle.replay.logs.metrics.ts @@ -7,7 +7,7 @@ import { export * from './index.bundle.base'; // TODO(v11): Export metrics here once we remove it from the base bundle. -export { logger, consoleLoggingIntegration } from '@sentry/core'; +export { logger, consoleLoggingIntegration } from '@sentry/core/browser'; export { replayIntegration, getReplay } from '@sentry-internal/replay'; diff --git a/packages/browser/src/index.bundle.tracing.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.logs.metrics.ts index 19b8118a5c04..eec04b9ee335 100644 --- a/packages/browser/src/index.bundle.tracing.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.logs.metrics.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { feedbackIntegrationShim, replayIntegrationShim } from '@sentry-internal/integration-shims'; registerSpanErrorInstrumentation(); @@ -6,7 +6,7 @@ registerSpanErrorInstrumentation(); export * from './index.bundle.base'; // TODO(v11): Export metrics here once we remove it from the base bundle. -export { logger, consoleLoggingIntegration } from '@sentry/core'; +export { logger, consoleLoggingIntegration } from '@sentry/core/browser'; export { getActiveSpan, @@ -18,7 +18,7 @@ export { startSpan, startSpanManual, withActiveSpan, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts index 5a531f6b33a9..6131da91aeb7 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.logs.metrics.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { feedbackAsyncIntegration } from './feedbackAsync'; registerSpanErrorInstrumentation(); @@ -18,7 +18,7 @@ export { withActiveSpan, logger, consoleLoggingIntegration, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index 47b43d48f376..66d34bdd7831 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { consoleLoggingIntegrationShim, elementTimingIntegrationShim, @@ -23,7 +23,7 @@ export { withActiveSpan, getSpanDescendants, setMeasurement, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts b/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts index 45c7299bf436..470f8b2279c6 100644 --- a/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts +++ b/packages/browser/src/index.bundle.tracing.replay.logs.metrics.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { feedbackIntegrationShim } from '@sentry-internal/integration-shims'; registerSpanErrorInstrumentation(); @@ -6,7 +6,7 @@ registerSpanErrorInstrumentation(); export * from './index.bundle.base'; // TODO(v11): Export metrics here once we remove it from the base bundle. -export { logger, consoleLoggingIntegration } from '@sentry/core'; +export { logger, consoleLoggingIntegration } from '@sentry/core/browser'; export { getActiveSpan, @@ -18,7 +18,7 @@ export { startSpan, startSpanManual, withActiveSpan, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index 63eb9a81c24a..5c56feada691 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { consoleLoggingIntegrationShim, elementTimingIntegrationShim, @@ -23,7 +23,7 @@ export { withActiveSpan, getSpanDescendants, setMeasurement, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index a385ad4b0792..44bcc0d2ef4a 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -1,4 +1,4 @@ -import { registerSpanErrorInstrumentation } from '@sentry/core'; +import { registerSpanErrorInstrumentation } from '@sentry/core/browser'; import { consoleLoggingIntegrationShim, elementTimingIntegrationShim, @@ -24,7 +24,7 @@ export { withActiveSpan, getSpanDescendants, setMeasurement, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { browserTracingIntegration, diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 844f6a170090..37b8751c1a99 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -15,7 +15,7 @@ export { rewriteFramesIntegration, consoleLoggingIntegration, createConsolaReporter, -} from '@sentry/core'; +} from '@sentry/core/browser'; export { replayIntegration, getReplay } from '@sentry-internal/replay'; export type { @@ -75,8 +75,8 @@ export { createLangChainCallbackHandler, instrumentLangChainEmbeddings, logger, -} from '@sentry/core'; -export type { Span, FeatureFlagsIntegration } from '@sentry/core'; +} from '@sentry/core/browser'; +export type { Span, FeatureFlagsIntegration } from '@sentry/core/browser'; export { makeBrowserOfflineTransport } from './transports/offline'; export { browserProfilingIntegration } from './profiling/integration'; export { spotlightBrowserIntegration } from './integrations/spotlight'; diff --git a/packages/browser/src/integrations-bundle/index.captureconsole.ts b/packages/browser/src/integrations-bundle/index.captureconsole.ts index a2187ae98798..3d25bf4edaf5 100644 --- a/packages/browser/src/integrations-bundle/index.captureconsole.ts +++ b/packages/browser/src/integrations-bundle/index.captureconsole.ts @@ -1 +1 @@ -export { captureConsoleIntegration } from '@sentry/core'; +export { captureConsoleIntegration } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.createlangchaincallbackhandler.ts b/packages/browser/src/integrations-bundle/index.createlangchaincallbackhandler.ts index 8a64eda45579..a7bdee8b6693 100644 --- a/packages/browser/src/integrations-bundle/index.createlangchaincallbackhandler.ts +++ b/packages/browser/src/integrations-bundle/index.createlangchaincallbackhandler.ts @@ -1 +1 @@ -export { createLangChainCallbackHandler } from '@sentry/core'; +export { createLangChainCallbackHandler } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.dedupe.ts b/packages/browser/src/integrations-bundle/index.dedupe.ts index 776d967c31a9..19ba1ad738d4 100644 --- a/packages/browser/src/integrations-bundle/index.dedupe.ts +++ b/packages/browser/src/integrations-bundle/index.dedupe.ts @@ -1 +1 @@ -export { dedupeIntegration } from '@sentry/core'; +export { dedupeIntegration } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.extraerrordata.ts b/packages/browser/src/integrations-bundle/index.extraerrordata.ts index 4306f9694902..7df49cf87be6 100644 --- a/packages/browser/src/integrations-bundle/index.extraerrordata.ts +++ b/packages/browser/src/integrations-bundle/index.extraerrordata.ts @@ -1 +1 @@ -export { extraErrorDataIntegration } from '@sentry/core'; +export { extraErrorDataIntegration } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.feedback.ts b/packages/browser/src/integrations-bundle/index.feedback.ts index f5c10b970690..2518eb82e776 100644 --- a/packages/browser/src/integrations-bundle/index.feedback.ts +++ b/packages/browser/src/integrations-bundle/index.feedback.ts @@ -4,4 +4,4 @@ export { getFeedback } from '@sentry-internal/feedback'; export { feedbackAsyncIntegration, feedbackAsyncIntegration as feedbackIntegration }; -export { captureFeedback } from '@sentry/core'; +export { captureFeedback } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.instrumentanthropicaiclient.ts b/packages/browser/src/integrations-bundle/index.instrumentanthropicaiclient.ts index d82909a524d8..ab7b3157953a 100644 --- a/packages/browser/src/integrations-bundle/index.instrumentanthropicaiclient.ts +++ b/packages/browser/src/integrations-bundle/index.instrumentanthropicaiclient.ts @@ -1 +1 @@ -export { instrumentAnthropicAiClient } from '@sentry/core'; +export { instrumentAnthropicAiClient } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.instrumentgooglegenaiclient.ts b/packages/browser/src/integrations-bundle/index.instrumentgooglegenaiclient.ts index ec58139c0681..9e8316dc7e43 100644 --- a/packages/browser/src/integrations-bundle/index.instrumentgooglegenaiclient.ts +++ b/packages/browser/src/integrations-bundle/index.instrumentgooglegenaiclient.ts @@ -1 +1 @@ -export { instrumentGoogleGenAIClient } from '@sentry/core'; +export { instrumentGoogleGenAIClient } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.instrumentlangchainembeddings.ts b/packages/browser/src/integrations-bundle/index.instrumentlangchainembeddings.ts index 644b8a2ef570..b8b733fc9907 100644 --- a/packages/browser/src/integrations-bundle/index.instrumentlangchainembeddings.ts +++ b/packages/browser/src/integrations-bundle/index.instrumentlangchainembeddings.ts @@ -1 +1 @@ -export { instrumentLangChainEmbeddings } from '@sentry/core'; +export { instrumentLangChainEmbeddings } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.instrumentlanggraph.ts b/packages/browser/src/integrations-bundle/index.instrumentlanggraph.ts index c7a8c0e9e591..e54333eed24a 100644 --- a/packages/browser/src/integrations-bundle/index.instrumentlanggraph.ts +++ b/packages/browser/src/integrations-bundle/index.instrumentlanggraph.ts @@ -1 +1 @@ -export { instrumentLangGraph } from '@sentry/core'; +export { instrumentLangGraph } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.instrumentopenaiclient.ts b/packages/browser/src/integrations-bundle/index.instrumentopenaiclient.ts index 5371961ff03a..813ad7b2a9fb 100644 --- a/packages/browser/src/integrations-bundle/index.instrumentopenaiclient.ts +++ b/packages/browser/src/integrations-bundle/index.instrumentopenaiclient.ts @@ -1 +1 @@ -export { instrumentOpenAiClient } from '@sentry/core'; +export { instrumentOpenAiClient } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.modulemetadata.ts b/packages/browser/src/integrations-bundle/index.modulemetadata.ts index c4f4a2b9cf75..b63da0e5a49d 100644 --- a/packages/browser/src/integrations-bundle/index.modulemetadata.ts +++ b/packages/browser/src/integrations-bundle/index.modulemetadata.ts @@ -1 +1 @@ -export { moduleMetadataIntegration } from '@sentry/core'; +export { moduleMetadataIntegration } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations-bundle/index.rewriteframes.ts b/packages/browser/src/integrations-bundle/index.rewriteframes.ts index 07ebaf6666f5..fbdc2d071d3e 100644 --- a/packages/browser/src/integrations-bundle/index.rewriteframes.ts +++ b/packages/browser/src/integrations-bundle/index.rewriteframes.ts @@ -1 +1 @@ -export { rewriteFramesIntegration } from '@sentry/core'; +export { rewriteFramesIntegration } from '@sentry/core/browser'; diff --git a/packages/browser/src/integrations/breadcrumbs.ts b/packages/browser/src/integrations/breadcrumbs.ts index de99621bf52f..7378ffc7c377 100644 --- a/packages/browser/src/integrations/breadcrumbs.ts +++ b/packages/browser/src/integrations/breadcrumbs.ts @@ -14,7 +14,7 @@ import type { IntegrationFn, XhrBreadcrumbData, XhrBreadcrumbHint, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { addBreadcrumb, addConsoleInstrumentationHandler, @@ -29,7 +29,7 @@ import { parseUrl, safeJoin, severityLevelFromString, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { FetchHint, XhrHint } from '@sentry-internal/browser-utils'; import { addClickKeypressInstrumentationHandler, diff --git a/packages/browser/src/integrations/browserapierrors.ts b/packages/browser/src/integrations/browserapierrors.ts index cd32435fa5b0..0688bcf1bb76 100644 --- a/packages/browser/src/integrations/browserapierrors.ts +++ b/packages/browser/src/integrations/browserapierrors.ts @@ -1,5 +1,5 @@ -import type { IntegrationFn, WrappedFunction } from '@sentry/core'; -import { defineIntegration, fill, getFunctionName, getOriginalFunction } from '@sentry/core'; +import type { IntegrationFn, WrappedFunction } from '@sentry/core/browser'; +import { defineIntegration, fill, getFunctionName, getOriginalFunction } from '@sentry/core/browser'; import { WINDOW, wrap } from '../helpers'; // Using a comma-separated string and split for smaller bundle size vs an array literal diff --git a/packages/browser/src/integrations/browsersession.ts b/packages/browser/src/integrations/browsersession.ts index 23fdb4087af9..7d339baa42d5 100644 --- a/packages/browser/src/integrations/browsersession.ts +++ b/packages/browser/src/integrations/browsersession.ts @@ -1,4 +1,4 @@ -import { captureSession, debug, defineIntegration, getIsolationScope, startSession } from '@sentry/core'; +import { captureSession, debug, defineIntegration, getIsolationScope, startSession } from '@sentry/core/browser'; import { addHistoryInstrumentationHandler } from '@sentry-internal/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/integrations/contextlines.ts b/packages/browser/src/integrations/contextlines.ts index 07dae0b9dc32..70da4bac7504 100644 --- a/packages/browser/src/integrations/contextlines.ts +++ b/packages/browser/src/integrations/contextlines.ts @@ -1,5 +1,5 @@ -import type { Event, IntegrationFn, StackFrame } from '@sentry/core'; -import { addContextToFrame, defineIntegration, GLOBAL_OBJ, stripUrlQueryAndFragment } from '@sentry/core'; +import type { Event, IntegrationFn, StackFrame } from '@sentry/core/browser'; +import { addContextToFrame, defineIntegration, GLOBAL_OBJ, stripUrlQueryAndFragment } from '@sentry/core/browser'; const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; diff --git a/packages/browser/src/integrations/culturecontext.ts b/packages/browser/src/integrations/culturecontext.ts index f2b705e3e9a9..9701dbb4725d 100644 --- a/packages/browser/src/integrations/culturecontext.ts +++ b/packages/browser/src/integrations/culturecontext.ts @@ -1,5 +1,5 @@ -import type { CultureContext, IntegrationFn } from '@sentry/core'; -import { defineIntegration } from '@sentry/core'; +import type { CultureContext, IntegrationFn } from '@sentry/core/browser'; +import { defineIntegration } from '@sentry/core/browser'; import { WINDOW } from '../helpers'; const INTEGRATION_NAME = 'CultureContext'; diff --git a/packages/browser/src/integrations/featureFlags/growthbook/integration.ts b/packages/browser/src/integrations/featureFlags/growthbook/integration.ts index 560918535cce..38ae92009063 100644 --- a/packages/browser/src/integrations/featureFlags/growthbook/integration.ts +++ b/packages/browser/src/integrations/featureFlags/growthbook/integration.ts @@ -1,5 +1,5 @@ -import type { IntegrationFn } from '@sentry/core'; -import { growthbookIntegration as coreGrowthbookIntegration } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/core/browser'; +import { growthbookIntegration as coreGrowthbookIntegration } from '@sentry/core/browser'; import type { GrowthBookClass } from './types'; /** diff --git a/packages/browser/src/integrations/featureFlags/launchdarkly/integration.ts b/packages/browser/src/integrations/featureFlags/launchdarkly/integration.ts index 822e4b1d7f80..5283dbb7434a 100644 --- a/packages/browser/src/integrations/featureFlags/launchdarkly/integration.ts +++ b/packages/browser/src/integrations/featureFlags/launchdarkly/integration.ts @@ -1,10 +1,10 @@ -import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core'; +import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core/browser'; import { _INTERNAL_addFeatureFlagToActiveSpan, _INTERNAL_copyFlagsFromScopeToEvent, _INTERNAL_insertFlagToScope, defineIntegration, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { LDContext, LDEvaluationDetail, LDInspectionFlagUsedHandler } from './types'; /** diff --git a/packages/browser/src/integrations/featureFlags/openfeature/integration.ts b/packages/browser/src/integrations/featureFlags/openfeature/integration.ts index 85aedbf779f9..fd4b01ad38eb 100644 --- a/packages/browser/src/integrations/featureFlags/openfeature/integration.ts +++ b/packages/browser/src/integrations/featureFlags/openfeature/integration.ts @@ -13,13 +13,13 @@ * OpenFeature.addHooks(new Sentry.OpenFeatureIntegrationHook()); * ``` */ -import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core'; +import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core/browser'; import { _INTERNAL_addFeatureFlagToActiveSpan, _INTERNAL_copyFlagsFromScopeToEvent, _INTERNAL_insertFlagToScope, defineIntegration, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { EvaluationDetails, HookContext, HookHints, JsonValue, OpenFeatureHook } from './types'; export const openFeatureIntegration = defineIntegration(() => { diff --git a/packages/browser/src/integrations/featureFlags/statsig/integration.ts b/packages/browser/src/integrations/featureFlags/statsig/integration.ts index 9aef234045b5..94df3857b79e 100644 --- a/packages/browser/src/integrations/featureFlags/statsig/integration.ts +++ b/packages/browser/src/integrations/featureFlags/statsig/integration.ts @@ -1,10 +1,10 @@ -import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core'; +import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core/browser'; import { _INTERNAL_addFeatureFlagToActiveSpan, _INTERNAL_copyFlagsFromScopeToEvent, _INTERNAL_insertFlagToScope, defineIntegration, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { FeatureGate, StatsigClient } from './types'; /** diff --git a/packages/browser/src/integrations/featureFlags/unleash/integration.ts b/packages/browser/src/integrations/featureFlags/unleash/integration.ts index c822b49f8810..b9421efe0d37 100644 --- a/packages/browser/src/integrations/featureFlags/unleash/integration.ts +++ b/packages/browser/src/integrations/featureFlags/unleash/integration.ts @@ -1,4 +1,4 @@ -import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core'; +import type { Client, Event, EventHint, IntegrationFn } from '@sentry/core/browser'; import { _INTERNAL_addFeatureFlagToActiveSpan, _INTERNAL_copyFlagsFromScopeToEvent, @@ -6,7 +6,7 @@ import { debug, defineIntegration, fill, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { DEBUG_BUILD } from '../../../debug-build'; import type { UnleashClient, UnleashClientClass } from './types'; diff --git a/packages/browser/src/integrations/globalhandlers.ts b/packages/browser/src/integrations/globalhandlers.ts index 70b3516b63b1..00deac133889 100644 --- a/packages/browser/src/integrations/globalhandlers.ts +++ b/packages/browser/src/integrations/globalhandlers.ts @@ -1,4 +1,4 @@ -import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/core'; +import type { Client, Event, IntegrationFn, Primitive, StackParser } from '@sentry/core/browser'; import { addGlobalErrorInstrumentationHandler, addGlobalUnhandledRejectionInstrumentationHandler, @@ -11,7 +11,7 @@ import { isString, stripDataUrlContent, UNKNOWN_FUNCTION, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { BrowserClient } from '../client'; import { DEBUG_BUILD } from '../debug-build'; import { eventFromUnknownInput } from '../eventbuilder'; diff --git a/packages/browser/src/integrations/graphqlClient.ts b/packages/browser/src/integrations/graphqlClient.ts index 51a3fe939f23..74b1b425aaa3 100644 --- a/packages/browser/src/integrations/graphqlClient.ts +++ b/packages/browser/src/integrations/graphqlClient.ts @@ -1,4 +1,4 @@ -import type { Client, IntegrationFn } from '@sentry/core'; +import type { Client, IntegrationFn } from '@sentry/core/browser'; import { defineIntegration, isString, @@ -7,7 +7,7 @@ import { SEMANTIC_ATTRIBUTE_URL_FULL, spanToJSON, stringMatchesSomePattern, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { FetchHint, XhrHint } from '@sentry-internal/browser-utils'; import { getBodyString, getFetchRequestArgBody, SENTRY_XHR_DATA_KEY } from '@sentry-internal/browser-utils'; diff --git a/packages/browser/src/integrations/httpclient.ts b/packages/browser/src/integrations/httpclient.ts index 76f32158f496..c2152f0ab78d 100644 --- a/packages/browser/src/integrations/httpclient.ts +++ b/packages/browser/src/integrations/httpclient.ts @@ -1,4 +1,4 @@ -import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/core'; +import type { Client, Event as SentryEvent, IntegrationFn, SentryWrappedXMLHttpRequest } from '@sentry/core/browser'; import { addExceptionMechanism, addFetchInstrumentationHandler, @@ -9,7 +9,7 @@ import { GLOBAL_OBJ, isSentryRequestUrl, supportsNativeFetch, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { addXhrInstrumentationHandler, SENTRY_XHR_DATA_KEY } from '@sentry-internal/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; diff --git a/packages/browser/src/integrations/httpcontext.ts b/packages/browser/src/integrations/httpcontext.ts index 9517b2364e83..dc03f59399e9 100644 --- a/packages/browser/src/integrations/httpcontext.ts +++ b/packages/browser/src/integrations/httpcontext.ts @@ -1,4 +1,4 @@ -import { defineIntegration } from '@sentry/core'; +import { defineIntegration } from '@sentry/core/browser'; import { getHttpRequestData, WINDOW } from '../helpers'; /** diff --git a/packages/browser/src/integrations/linkederrors.ts b/packages/browser/src/integrations/linkederrors.ts index d0eace11aadb..64b7f5a3edbd 100644 --- a/packages/browser/src/integrations/linkederrors.ts +++ b/packages/browser/src/integrations/linkederrors.ts @@ -1,5 +1,5 @@ -import type { IntegrationFn } from '@sentry/core'; -import { applyAggregateErrorsToEvent, defineIntegration } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/core/browser'; +import { applyAggregateErrorsToEvent, defineIntegration } from '@sentry/core/browser'; import { exceptionFromError } from '../eventbuilder'; interface LinkedErrorsOptions { diff --git a/packages/browser/src/integrations/reportingobserver.ts b/packages/browser/src/integrations/reportingobserver.ts index 571dca9db839..6e06e15646c0 100644 --- a/packages/browser/src/integrations/reportingobserver.ts +++ b/packages/browser/src/integrations/reportingobserver.ts @@ -1,4 +1,4 @@ -import type { Client, IntegrationFn } from '@sentry/core'; +import type { Client, IntegrationFn } from '@sentry/core/browser'; import { captureMessage, defineIntegration, @@ -6,7 +6,7 @@ import { GLOBAL_OBJ, supportsReportingObserver, withScope, -} from '@sentry/core'; +} from '@sentry/core/browser'; const WINDOW = GLOBAL_OBJ as typeof GLOBAL_OBJ & Window; diff --git a/packages/browser/src/integrations/spanstreaming.ts b/packages/browser/src/integrations/spanstreaming.ts index ad6a35d1813b..9f82904419c6 100644 --- a/packages/browser/src/integrations/spanstreaming.ts +++ b/packages/browser/src/integrations/spanstreaming.ts @@ -1,4 +1,4 @@ -import type { IntegrationFn } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/core/browser'; import { captureSpan, debug, @@ -7,7 +7,7 @@ import { isStreamedBeforeSendSpanCallback, SpanBuffer, spanIsSampled, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; export const spanStreamingIntegration = defineIntegration(() => { diff --git a/packages/browser/src/integrations/spotlight.ts b/packages/browser/src/integrations/spotlight.ts index bea72e029a97..233dca1ced87 100644 --- a/packages/browser/src/integrations/spotlight.ts +++ b/packages/browser/src/integrations/spotlight.ts @@ -1,5 +1,5 @@ -import type { Client, Envelope, Event, IntegrationFn } from '@sentry/core'; -import { debug, defineIntegration, serializeEnvelope } from '@sentry/core'; +import type { Client, Envelope, Event, IntegrationFn } from '@sentry/core/browser'; +import { debug, defineIntegration, serializeEnvelope } from '@sentry/core/browser'; import { getNativeImplementation } from '@sentry-internal/browser-utils'; import { DEBUG_BUILD } from '../debug-build'; import type { WINDOW } from '../helpers'; diff --git a/packages/browser/src/integrations/view-hierarchy.ts b/packages/browser/src/integrations/view-hierarchy.ts index fa35ad7e00a2..edb959eca3f9 100644 --- a/packages/browser/src/integrations/view-hierarchy.ts +++ b/packages/browser/src/integrations/view-hierarchy.ts @@ -1,5 +1,5 @@ -import type { Attachment, Event, EventHint, ViewHierarchyData, ViewHierarchyWindow } from '@sentry/core'; -import { defineIntegration, getComponentName } from '@sentry/core'; +import type { Attachment, Event, EventHint, ViewHierarchyData, ViewHierarchyWindow } from '@sentry/core/browser'; +import { defineIntegration, getComponentName } from '@sentry/core/browser'; import { WINDOW } from '../helpers'; interface OnElementArgs { diff --git a/packages/browser/src/integrations/webWorker.ts b/packages/browser/src/integrations/webWorker.ts index 147135526ec3..a79dc463278a 100644 --- a/packages/browser/src/integrations/webWorker.ts +++ b/packages/browser/src/integrations/webWorker.ts @@ -1,5 +1,5 @@ -import type { DebugImage, Integration, IntegrationFn } from '@sentry/core'; -import { captureEvent, debug, defineIntegration, getClient, isPlainObject, isPrimitive } from '@sentry/core'; +import type { DebugImage, Integration, IntegrationFn } from '@sentry/core/browser'; +import { captureEvent, debug, defineIntegration, getClient, isPlainObject, isPrimitive } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import { eventFromUnknownInput } from '../eventbuilder'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/pluggable-exports-bundle/index.multiplexedtransport.ts b/packages/browser/src/pluggable-exports-bundle/index.multiplexedtransport.ts index a7d637d9e62f..a0b137cb1a53 100644 --- a/packages/browser/src/pluggable-exports-bundle/index.multiplexedtransport.ts +++ b/packages/browser/src/pluggable-exports-bundle/index.multiplexedtransport.ts @@ -1 +1 @@ -export { makeMultiplexedTransport } from '@sentry/core'; +export { makeMultiplexedTransport } from '@sentry/core/browser'; diff --git a/packages/browser/src/profiling/UIProfiler.ts b/packages/browser/src/profiling/UIProfiler.ts index 932b442a4b6e..aa9c6a5f5fdf 100644 --- a/packages/browser/src/profiling/UIProfiler.ts +++ b/packages/browser/src/profiling/UIProfiler.ts @@ -1,4 +1,4 @@ -import type { Client, ContinuousProfiler, ProfileChunk, ProfileChunkEnvelope, Span } from '@sentry/core'; +import type { Client, ContinuousProfiler, ProfileChunk, ProfileChunkEnvelope, Span } from '@sentry/core/browser'; import { createEnvelope, debug, @@ -7,7 +7,7 @@ import { getRootSpan, getSdkMetadataForEnvelopeHeader, uuid4, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { BrowserOptions } from '../client'; import { DEBUG_BUILD } from './../debug-build'; import type { JSSelfProfiler } from './jsSelfProfiling'; diff --git a/packages/browser/src/profiling/index.ts b/packages/browser/src/profiling/index.ts index 5847c070dd48..3f1fe9a82ed4 100644 --- a/packages/browser/src/profiling/index.ts +++ b/packages/browser/src/profiling/index.ts @@ -1,5 +1,5 @@ -import type { Profiler } from '@sentry/core'; -import { debug, getClient } from '@sentry/core'; +import type { Profiler } from '@sentry/core/browser'; +import { debug, getClient } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; /** diff --git a/packages/browser/src/profiling/integration.ts b/packages/browser/src/profiling/integration.ts index 84cd33588320..22706117fa74 100644 --- a/packages/browser/src/profiling/integration.ts +++ b/packages/browser/src/profiling/integration.ts @@ -1,5 +1,5 @@ -import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/core'; -import { debug, defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled } from '@sentry/core'; +import type { EventEnvelope, IntegrationFn, Profile, Span } from '@sentry/core/browser'; +import { debug, defineIntegration, getActiveSpan, getRootSpan, hasSpansEnabled } from '@sentry/core/browser'; import type { BrowserOptions } from '../client'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/profiling/startProfileForSpan.ts b/packages/browser/src/profiling/startProfileForSpan.ts index 6eaaa016d822..6c36c6bf84aa 100644 --- a/packages/browser/src/profiling/startProfileForSpan.ts +++ b/packages/browser/src/profiling/startProfileForSpan.ts @@ -1,5 +1,5 @@ -import type { Span } from '@sentry/core'; -import { debug, getCurrentScope, spanToJSON, timestampInSeconds, uuid4 } from '@sentry/core'; +import type { Span } from '@sentry/core/browser'; +import { debug, getCurrentScope, spanToJSON, timestampInSeconds, uuid4 } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; import type { JSSelfProfile } from './jsSelfProfiling'; diff --git a/packages/browser/src/profiling/utils.ts b/packages/browser/src/profiling/utils.ts index f0d067c841d8..12446e6fb986 100644 --- a/packages/browser/src/profiling/utils.ts +++ b/packages/browser/src/profiling/utils.ts @@ -10,7 +10,7 @@ import type { ProfileChunk, Span, ThreadCpuProfile, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { browserPerformanceTimeOrigin, debug, @@ -22,7 +22,7 @@ import { spanToJSON, timestampInSeconds, uuid4, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { BrowserOptions } from '../client'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/report-dialog.ts b/packages/browser/src/report-dialog.ts index 03255a7db91d..beb6f7ec9c08 100644 --- a/packages/browser/src/report-dialog.ts +++ b/packages/browser/src/report-dialog.ts @@ -1,5 +1,5 @@ -import type { ReportDialogOptions } from '@sentry/core'; -import { debug, getClient, getCurrentScope, getReportDialogEndpoint, lastEventId } from '@sentry/core'; +import type { ReportDialogOptions } from '@sentry/core/browser'; +import { debug, getClient, getCurrentScope, getReportDialogEndpoint, lastEventId } from '@sentry/core/browser'; import { DEBUG_BUILD } from './debug-build'; import { WINDOW } from './helpers'; diff --git a/packages/browser/src/sdk.ts b/packages/browser/src/sdk.ts index 8a457f858f3c..68a48ec461d1 100644 --- a/packages/browser/src/sdk.ts +++ b/packages/browser/src/sdk.ts @@ -1,4 +1,4 @@ -import type { Client, Integration, Options } from '@sentry/core'; +import type { Client, Integration, Options } from '@sentry/core/browser'; import { conversationIdIntegration, dedupeIntegration, @@ -7,7 +7,7 @@ import { inboundFiltersIntegration, initAndBind, stackParserFromStackParserOptions, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { BrowserClientOptions, BrowserOptions } from './client'; import { BrowserClient } from './client'; import { breadcrumbsIntegration } from './integrations/breadcrumbs'; diff --git a/packages/browser/src/stack-parsers.ts b/packages/browser/src/stack-parsers.ts index cb74bc1e6ce6..9214dac42707 100644 --- a/packages/browser/src/stack-parsers.ts +++ b/packages/browser/src/stack-parsers.ts @@ -23,8 +23,8 @@ // CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE // OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -import type { StackFrame, StackLineParser, StackLineParserFn } from '@sentry/core'; -import { createStackParser, UNKNOWN_FUNCTION } from '@sentry/core'; +import type { StackFrame, StackLineParser, StackLineParserFn } from '@sentry/core/browser'; +import { createStackParser, UNKNOWN_FUNCTION } from '@sentry/core/browser'; const OPERA10_PRIORITY = 10; const OPERA11_PRIORITY = 20; diff --git a/packages/browser/src/tracing/backgroundtab.ts b/packages/browser/src/tracing/backgroundtab.ts index f8aeca761d85..c484bc0e52c2 100644 --- a/packages/browser/src/tracing/backgroundtab.ts +++ b/packages/browser/src/tracing/backgroundtab.ts @@ -1,4 +1,4 @@ -import { debug, getActiveSpan, getRootSpan, SPAN_STATUS_ERROR, spanToJSON } from '@sentry/core'; +import { debug, getActiveSpan, getRootSpan, SPAN_STATUS_ERROR, spanToJSON } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/tracing/browserTracingIntegration.ts b/packages/browser/src/tracing/browserTracingIntegration.ts index 34a9609099ad..08acf99761fc 100644 --- a/packages/browser/src/tracing/browserTracingIntegration.ts +++ b/packages/browser/src/tracing/browserTracingIntegration.ts @@ -7,7 +7,7 @@ import type { Span, StartSpanOptions, TransactionSource, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { addNonEnumerableProperty, browserPerformanceTimeOrigin, @@ -36,7 +36,7 @@ import { startInactiveSpan, timestampInSeconds, TRACING_DEFAULTS, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { addHistoryInstrumentationHandler, addPerformanceEntries, diff --git a/packages/browser/src/tracing/linkedTraces.ts b/packages/browser/src/tracing/linkedTraces.ts index 4768ac7c66a1..8b13ff99fb35 100644 --- a/packages/browser/src/tracing/linkedTraces.ts +++ b/packages/browser/src/tracing/linkedTraces.ts @@ -1,4 +1,4 @@ -import type { Client, PropagationContext, Span, SpanContextData } from '@sentry/core'; +import type { Client, PropagationContext, Span, SpanContextData } from '@sentry/core/browser'; import { debug, getCurrentScope, @@ -7,7 +7,7 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_LINK_ATTRIBUTE_LINK_TYPE, spanToJSON, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../exports'; @@ -231,7 +231,7 @@ export function getPreviousTraceFromSessionStorage(): PreviousTraceInfo | undefi } /** - * see {@link import('@sentry/core').spanIsSampled} + * see {@link import('@sentry/core/browser').spanIsSampled} */ export function spanContextSampled(ctx: SpanContextData): boolean { return ctx.traceFlags === 0x1; diff --git a/packages/browser/src/tracing/reportPageLoaded.ts b/packages/browser/src/tracing/reportPageLoaded.ts index 2d3d4a4991a4..fbd5e3a49933 100644 --- a/packages/browser/src/tracing/reportPageLoaded.ts +++ b/packages/browser/src/tracing/reportPageLoaded.ts @@ -1,5 +1,5 @@ -import type { Client } from '@sentry/core'; -import { getClient } from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import { getClient } from '@sentry/core/browser'; /** * Manually report the end of the page load, resulting in the SDK ending the pageload span. diff --git a/packages/browser/src/tracing/request.ts b/packages/browser/src/tracing/request.ts index b393f0585b5b..b0e43f2201be 100644 --- a/packages/browser/src/tracing/request.ts +++ b/packages/browser/src/tracing/request.ts @@ -7,7 +7,7 @@ import type { SentryWrappedXMLHttpRequest, Span, SpanTimeInput, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler, @@ -29,7 +29,7 @@ import { stripDataUrlContent, stripUrlQueryAndFragment, timestampInSeconds, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { XhrHint } from '@sentry-internal/browser-utils'; import { addPerformanceInstrumentationHandler, diff --git a/packages/browser/src/tracing/setActiveSpan.ts b/packages/browser/src/tracing/setActiveSpan.ts index 5e3b537d4b6d..be1cb52adc06 100644 --- a/packages/browser/src/tracing/setActiveSpan.ts +++ b/packages/browser/src/tracing/setActiveSpan.ts @@ -1,5 +1,5 @@ -import type { Span } from '@sentry/core'; -import { _INTERNAL_setSpanForScope, getActiveSpan, getCurrentScope } from '@sentry/core'; +import type { Span } from '@sentry/core/browser'; +import { _INTERNAL_setSpanForScope, getActiveSpan, getCurrentScope } from '@sentry/core/browser'; /** * Sets an inactive span active on the current scope. diff --git a/packages/browser/src/transports/fetch.ts b/packages/browser/src/transports/fetch.ts index f6683c7005de..f5b3f2d780e8 100644 --- a/packages/browser/src/transports/fetch.ts +++ b/packages/browser/src/transports/fetch.ts @@ -1,5 +1,5 @@ -import type { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/core'; -import { createTransport, makePromiseBuffer } from '@sentry/core'; +import type { Transport, TransportMakeRequestResponse, TransportRequest } from '@sentry/core/browser'; +import { createTransport, makePromiseBuffer } from '@sentry/core/browser'; import { clearCachedImplementation, getNativeImplementation } from '@sentry-internal/browser-utils'; import type { WINDOW } from '../helpers'; import type { BrowserTransportOptions } from './types'; diff --git a/packages/browser/src/transports/offline.ts b/packages/browser/src/transports/offline.ts index c644e72fbf39..c965e3aa5c15 100644 --- a/packages/browser/src/transports/offline.ts +++ b/packages/browser/src/transports/offline.ts @@ -1,5 +1,11 @@ -import type { BaseTransportOptions, Envelope, OfflineStore, OfflineTransportOptions, Transport } from '@sentry/core'; -import { makeOfflineTransport, parseEnvelope, serializeEnvelope } from '@sentry/core'; +import type { + BaseTransportOptions, + Envelope, + OfflineStore, + OfflineTransportOptions, + Transport, +} from '@sentry/core/browser'; +import { makeOfflineTransport, parseEnvelope, serializeEnvelope } from '@sentry/core/browser'; import { WINDOW } from '../helpers'; import { makeFetchTransport } from './fetch'; diff --git a/packages/browser/src/transports/types.ts b/packages/browser/src/transports/types.ts index a304e9f93d66..e2a00e9a12d8 100644 --- a/packages/browser/src/transports/types.ts +++ b/packages/browser/src/transports/types.ts @@ -1,4 +1,4 @@ -import type { BaseTransportOptions } from '@sentry/core'; +import type { BaseTransportOptions } from '@sentry/core/browser'; export interface BrowserTransportOptions extends BaseTransportOptions { /** Fetch API init parameters. Used by the FetchTransport */ diff --git a/packages/browser/src/userfeedback.ts b/packages/browser/src/userfeedback.ts index bc6fd248b480..f77699dd1c75 100644 --- a/packages/browser/src/userfeedback.ts +++ b/packages/browser/src/userfeedback.ts @@ -1,5 +1,5 @@ -import type { DsnComponents, EventEnvelope, SdkMetadata, UserFeedback, UserFeedbackItem } from '@sentry/core'; -import { createEnvelope, dsnToString } from '@sentry/core'; +import type { DsnComponents, EventEnvelope, SdkMetadata, UserFeedback, UserFeedbackItem } from '@sentry/core/browser'; +import { createEnvelope, dsnToString } from '@sentry/core/browser'; /** * Creates an envelope from a user feedback. diff --git a/packages/browser/src/utils/detectBrowserExtension.ts b/packages/browser/src/utils/detectBrowserExtension.ts index 95ad7cebcf06..86ba33ba7727 100644 --- a/packages/browser/src/utils/detectBrowserExtension.ts +++ b/packages/browser/src/utils/detectBrowserExtension.ts @@ -1,4 +1,4 @@ -import { consoleSandbox, getLocationHref } from '@sentry/core'; +import { consoleSandbox, getLocationHref } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/src/utils/lazyLoadIntegration.ts b/packages/browser/src/utils/lazyLoadIntegration.ts index a24da592faff..f348681adba5 100644 --- a/packages/browser/src/utils/lazyLoadIntegration.ts +++ b/packages/browser/src/utils/lazyLoadIntegration.ts @@ -1,5 +1,5 @@ -import type { IntegrationFn } from '@sentry/core'; -import { getClient, SDK_VERSION } from '@sentry/core'; +import type { IntegrationFn } from '@sentry/core/browser'; +import { getClient, SDK_VERSION } from '@sentry/core/browser'; import type { BrowserClient } from '../client'; import { WINDOW } from '../helpers'; diff --git a/packages/browser/test/client.test.ts b/packages/browser/test/client.test.ts index 27135b4fc9a9..9861c9e428ec 100644 --- a/packages/browser/test/client.test.ts +++ b/packages/browser/test/client.test.ts @@ -2,14 +2,14 @@ * @vitest-environment jsdom */ -import * as sentryCore from '@sentry/core'; -import { Scope } from '@sentry/core'; +import * as sentryCore from '@sentry/core/browser'; +import { Scope } from '@sentry/core/browser'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { applyDefaultOptions, BrowserClient } from '../src/client'; import { WINDOW } from '../src/helpers'; import { getDefaultBrowserClientOptions } from './helper/browser-client-options'; -vi.mock('@sentry/core', async requireActual => { +vi.mock('@sentry/core/browser', async requireActual => { return { ...((await requireActual()) as any), _INTERNAL_flushLogsBuffer: vi.fn(), diff --git a/packages/browser/test/diagnose-sdk.test.ts b/packages/browser/test/diagnose-sdk.test.ts index 85b60047361e..6161891424b2 100644 --- a/packages/browser/test/diagnose-sdk.test.ts +++ b/packages/browser/test/diagnose-sdk.test.ts @@ -2,13 +2,13 @@ * @vitest-environment jsdom */ -import type { Client } from '@sentry/core'; -import * as sentryCore from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import * as sentryCore from '@sentry/core/browser'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { diagnoseSdkConnectivity } from '../src/diagnose-sdk'; // Mock the @sentry/core module -vi.mock('@sentry/core', async requireActual => { +vi.mock('@sentry/core/browser', async requireActual => { return { ...((await requireActual()) as any), getClient: vi.fn(), diff --git a/packages/browser/test/eventbuilder.test.ts b/packages/browser/test/eventbuilder.test.ts index ef233ed58a1f..bc99c9c95e49 100644 --- a/packages/browser/test/eventbuilder.test.ts +++ b/packages/browser/test/eventbuilder.test.ts @@ -2,12 +2,12 @@ * @vitest-environment jsdom */ -import { addNonEnumerableProperty } from '@sentry/core'; +import { addNonEnumerableProperty } from '@sentry/core/browser'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { defaultStackParser } from '../src'; import { eventFromMessage, eventFromUnknownInput, extractMessage, extractType } from '../src/eventbuilder'; -vi.mock('@sentry/core', async requireActual => { +vi.mock('@sentry/core/browser', async requireActual => { return { ...((await requireActual()) as any), getClient() { diff --git a/packages/browser/test/helper/browser-client-options.ts b/packages/browser/test/helper/browser-client-options.ts index 237f3cec0e05..825bfb47a672 100644 --- a/packages/browser/test/helper/browser-client-options.ts +++ b/packages/browser/test/helper/browser-client-options.ts @@ -1,4 +1,4 @@ -import { createTransport, resolvedSyncPromise } from '@sentry/core'; +import { createTransport, resolvedSyncPromise } from '@sentry/core/browser'; import type { BrowserClientOptions } from '../../src/client'; export function getDefaultBrowserClientOptions(options: Partial = {}): BrowserClientOptions { diff --git a/packages/browser/test/helpers.test.ts b/packages/browser/test/helpers.test.ts index 3031ceae19aa..9a14db35c872 100644 --- a/packages/browser/test/helpers.test.ts +++ b/packages/browser/test/helpers.test.ts @@ -1,4 +1,4 @@ -import type { WrappedFunction } from '@sentry/core'; +import type { WrappedFunction } from '@sentry/core/browser'; import { describe, expect, it, vi } from 'vitest'; import { wrap } from '../src/helpers'; diff --git a/packages/browser/test/index.bundle.logs.metrics.test.ts b/packages/browser/test/index.bundle.logs.metrics.test.ts index 7d450dc1ced0..31d4254b9433 100644 --- a/packages/browser/test/index.bundle.logs.metrics.test.ts +++ b/packages/browser/test/index.bundle.logs.metrics.test.ts @@ -1,4 +1,4 @@ -import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core'; +import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core/browser'; import { spanStreamingIntegrationShim } from '@sentry-internal/integration-shims'; import { describe, expect, it } from 'vitest'; import * as LogsMetricsBundle from '../src/index.bundle.logs.metrics'; diff --git a/packages/browser/test/index.bundle.replay.logs.metrics.test.ts b/packages/browser/test/index.bundle.replay.logs.metrics.test.ts index d6bb995fae09..5e39b4111b63 100644 --- a/packages/browser/test/index.bundle.replay.logs.metrics.test.ts +++ b/packages/browser/test/index.bundle.replay.logs.metrics.test.ts @@ -1,4 +1,4 @@ -import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core'; +import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core/browser'; import { browserTracingIntegrationShim, feedbackIntegrationShim, diff --git a/packages/browser/test/index.bundle.tracing.logs.metrics.test.ts b/packages/browser/test/index.bundle.tracing.logs.metrics.test.ts index 483a4ae8a1f5..65cc58fbf028 100644 --- a/packages/browser/test/index.bundle.tracing.logs.metrics.test.ts +++ b/packages/browser/test/index.bundle.tracing.logs.metrics.test.ts @@ -1,4 +1,4 @@ -import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core'; +import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core/browser'; import { feedbackIntegrationShim, replayIntegrationShim } from '@sentry-internal/integration-shims'; import { describe, expect, it } from 'vitest'; import { browserTracingIntegration, spanStreamingIntegration } from '../src'; diff --git a/packages/browser/test/index.bundle.tracing.replay.feedback.logs.metrics.test.ts b/packages/browser/test/index.bundle.tracing.replay.feedback.logs.metrics.test.ts index 0c474b195bc8..e4b88fab24d7 100644 --- a/packages/browser/test/index.bundle.tracing.replay.feedback.logs.metrics.test.ts +++ b/packages/browser/test/index.bundle.tracing.replay.feedback.logs.metrics.test.ts @@ -1,4 +1,4 @@ -import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core'; +import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core/browser'; import { describe, expect, it } from 'vitest'; import { browserTracingIntegration, diff --git a/packages/browser/test/index.bundle.tracing.replay.logs.metrics.test.ts b/packages/browser/test/index.bundle.tracing.replay.logs.metrics.test.ts index 4848de24caea..f8571872ba95 100644 --- a/packages/browser/test/index.bundle.tracing.replay.logs.metrics.test.ts +++ b/packages/browser/test/index.bundle.tracing.replay.logs.metrics.test.ts @@ -1,4 +1,4 @@ -import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core'; +import { logger as coreLogger, metrics as coreMetrics } from '@sentry/core/browser'; import { feedbackIntegrationShim } from '@sentry-internal/integration-shims'; import { describe, expect, it } from 'vitest'; import { browserTracingIntegration, replayIntegration, spanStreamingIntegration } from '../src'; diff --git a/packages/browser/test/index.test.ts b/packages/browser/test/index.test.ts index 9a30596832e4..b662352bf3e3 100644 --- a/packages/browser/test/index.test.ts +++ b/packages/browser/test/index.test.ts @@ -9,8 +9,8 @@ import { getReportDialogEndpoint, lastEventId, SDK_VERSION, -} from '@sentry/core'; -import * as utils from '@sentry/core'; +} from '@sentry/core/browser'; +import * as utils from '@sentry/core/browser'; import type { Mock } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { @@ -37,7 +37,7 @@ const dsn = 'https://53039209a22b4ec1bcc296a3c9fdecd6@sentry.io/4291'; // eslint-disable-next-line no-var declare var global: any; -vi.mock('@sentry/core', async requireActual => { +vi.mock('@sentry/core/browser', async requireActual => { return { ...((await requireActual()) as any), getReportDialogEndpoint: vi.fn(), diff --git a/packages/browser/test/integrations/breadcrumbs.test.ts b/packages/browser/test/integrations/breadcrumbs.test.ts index 56df65c3a6ae..3ee91da9be13 100644 --- a/packages/browser/test/integrations/breadcrumbs.test.ts +++ b/packages/browser/test/integrations/breadcrumbs.test.ts @@ -1,4 +1,4 @@ -import * as SentryCore from '@sentry/core'; +import * as SentryCore from '@sentry/core/browser'; import { describe, expect, it, vi } from 'vitest'; import { breadcrumbsIntegration, BrowserClient, flush } from '../../src'; import { getDefaultBrowserClientOptions } from '../helper/browser-client-options'; diff --git a/packages/browser/test/integrations/contextlines.test.ts b/packages/browser/test/integrations/contextlines.test.ts index e34479cd644e..ffb062759d9c 100644 --- a/packages/browser/test/integrations/contextlines.test.ts +++ b/packages/browser/test/integrations/contextlines.test.ts @@ -1,4 +1,4 @@ -import type { StackFrame } from '@sentry/core'; +import type { StackFrame } from '@sentry/core/browser'; import { describe, expect, it } from 'vitest'; import { applySourceContextToFrame } from '../../src/integrations/contextlines'; diff --git a/packages/browser/test/integrations/graphqlClient.test.ts b/packages/browser/test/integrations/graphqlClient.test.ts index 1c4ab60d30f2..0ff1fb43161f 100644 --- a/packages/browser/test/integrations/graphqlClient.test.ts +++ b/packages/browser/test/integrations/graphqlClient.test.ts @@ -2,8 +2,8 @@ * @vitest-environment jsdom */ -import type { Client } from '@sentry/core'; -import { SentrySpan, spanToJSON } from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import { SentrySpan, spanToJSON } from '@sentry/core/browser'; import type { FetchHint, XhrHint } from '@sentry-internal/browser-utils'; import { SENTRY_XHR_DATA_KEY } from '@sentry-internal/browser-utils'; import { describe, expect, test } from 'vitest'; diff --git a/packages/browser/test/integrations/reportingobserver.test.ts b/packages/browser/test/integrations/reportingobserver.test.ts index 4376977a1b1a..18ef38b7a097 100644 --- a/packages/browser/test/integrations/reportingobserver.test.ts +++ b/packages/browser/test/integrations/reportingobserver.test.ts @@ -1,5 +1,5 @@ -import type { Client } from '@sentry/core'; -import * as SentryCore from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import * as SentryCore from '@sentry/core/browser'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { reportingObserverIntegration } from '../../src/integrations/reportingobserver'; diff --git a/packages/browser/test/integrations/spanstreaming.test.ts b/packages/browser/test/integrations/spanstreaming.test.ts index 1d5d587290a3..cc51ef6e6c17 100644 --- a/packages/browser/test/integrations/spanstreaming.test.ts +++ b/packages/browser/test/integrations/spanstreaming.test.ts @@ -1,5 +1,5 @@ -import * as SentryCore from '@sentry/core'; -import { debug } from '@sentry/core'; +import * as SentryCore from '@sentry/core/browser'; +import { debug } from '@sentry/core/browser'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { BrowserClient, spanStreamingIntegration } from '../../src'; import { getDefaultBrowserClientOptions } from '../helper/browser-client-options'; @@ -15,8 +15,8 @@ const MockSpanBuffer = vi.hoisted(() => { return vi.fn(() => mockSpanBufferInstance); }); -vi.mock('@sentry/core', async () => { - const original = await vi.importActual('@sentry/core'); +vi.mock('@sentry/core/browser', async () => { + const original = await vi.importActual('@sentry/core/browser'); return { ...original, SpanBuffer: MockSpanBuffer, diff --git a/packages/browser/test/integrations/webWorker.test.ts b/packages/browser/test/integrations/webWorker.test.ts index c239e31bd638..e824486456da 100644 --- a/packages/browser/test/integrations/webWorker.test.ts +++ b/packages/browser/test/integrations/webWorker.test.ts @@ -2,13 +2,13 @@ * @vitest-environment jsdom */ -import * as SentryCore from '@sentry/core'; +import * as SentryCore from '@sentry/core/browser'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import * as helpers from '../../src/helpers'; import { INTEGRATION_NAME, registerWebWorker, webWorkerIntegration } from '../../src/integrations/webWorker'; // Mock @sentry/core -vi.mock('@sentry/core', async importActual => { +vi.mock('@sentry/core/browser', async importActual => { return { ...((await importActual()) as any), debug: { diff --git a/packages/browser/test/mocks/simpletransport.ts b/packages/browser/test/mocks/simpletransport.ts index 515b0f9c0865..9f2f527fba7d 100644 --- a/packages/browser/test/mocks/simpletransport.ts +++ b/packages/browser/test/mocks/simpletransport.ts @@ -1,4 +1,4 @@ -import { createTransport, resolvedSyncPromise } from '@sentry/core'; +import { createTransport, resolvedSyncPromise } from '@sentry/core/browser'; export function makeSimpleTransport() { return createTransport({ recordDroppedEvent: () => undefined }, () => resolvedSyncPromise({})); diff --git a/packages/browser/test/profiling/UIProfiler.test.ts b/packages/browser/test/profiling/UIProfiler.test.ts index b64ee35fc50e..7acc6af05af0 100644 --- a/packages/browser/test/profiling/UIProfiler.test.ts +++ b/packages/browser/test/profiling/UIProfiler.test.ts @@ -3,7 +3,7 @@ */ import * as Sentry from '@sentry/browser'; -import { debug, type Span } from '@sentry/core'; +import { debug, type Span } from '@sentry/core/browser'; import { afterEach, beforeEach, describe, expect, it, type Mock, vi } from 'vitest'; import type { BrowserOptions } from '../../src/index'; diff --git a/packages/browser/test/profiling/integration.test.ts b/packages/browser/test/profiling/integration.test.ts index f9d97230701c..f1e50e842dba 100644 --- a/packages/browser/test/profiling/integration.test.ts +++ b/packages/browser/test/profiling/integration.test.ts @@ -3,7 +3,7 @@ */ import * as Sentry from '@sentry/browser'; -import { debug } from '@sentry/core'; +import { debug } from '@sentry/core/browser'; import { describe, expect, it, vi } from 'vitest'; import type { BrowserClient } from '../../src/index'; import type { JSSelfProfile } from '../../src/profiling/jsSelfProfiling'; diff --git a/packages/browser/test/sdk.test.ts b/packages/browser/test/sdk.test.ts index b7972797182f..3d84da69e565 100644 --- a/packages/browser/test/sdk.test.ts +++ b/packages/browser/test/sdk.test.ts @@ -3,9 +3,9 @@ */ /* eslint-disable @typescript-eslint/unbound-method */ -import type { Integration } from '@sentry/core'; -import * as SentryCore from '@sentry/core'; -import { createTransport, resolvedSyncPromise } from '@sentry/core'; +import type { Integration } from '@sentry/core/browser'; +import * as SentryCore from '@sentry/core/browser'; +import { createTransport, resolvedSyncPromise } from '@sentry/core/browser'; import type { Mock } from 'vitest'; import { afterEach, describe, expect, it, test, vi } from 'vitest'; import type { BrowserOptions } from '../src'; diff --git a/packages/browser/test/tracekit/ie.test.ts b/packages/browser/test/tracekit/ie.test.ts index 7bf463d39f33..ad2328ac6e26 100644 --- a/packages/browser/test/tracekit/ie.test.ts +++ b/packages/browser/test/tracekit/ie.test.ts @@ -1,4 +1,4 @@ -import { createStackParser } from '@sentry/core'; +import { createStackParser } from '@sentry/core/browser'; import { describe, expect, it } from 'vitest'; import { exceptionFromError } from '../../src/eventbuilder'; import { chromeStackLineParser, geckoStackLineParser, winjsStackLineParser } from '../../src/stack-parsers'; diff --git a/packages/browser/test/tracekit/opera.test.ts b/packages/browser/test/tracekit/opera.test.ts index d109fb39ac9c..5c85ebe8efec 100644 --- a/packages/browser/test/tracekit/opera.test.ts +++ b/packages/browser/test/tracekit/opera.test.ts @@ -1,4 +1,4 @@ -import { createStackParser } from '@sentry/core'; +import { createStackParser } from '@sentry/core/browser'; import { describe, expect, it } from 'vitest'; import { exceptionFromError } from '../../src/eventbuilder'; import { defaultStackParser, opera10StackLineParser, opera11StackLineParser } from '../../src/stack-parsers'; diff --git a/packages/browser/test/tracing/backgroundtab.test.ts b/packages/browser/test/tracing/backgroundtab.test.ts index 8d76e895848f..44e827fc9e64 100644 --- a/packages/browser/test/tracing/backgroundtab.test.ts +++ b/packages/browser/test/tracing/backgroundtab.test.ts @@ -2,7 +2,7 @@ * @vitest-environment jsdom */ -import { getCurrentScope, setCurrentClient } from '@sentry/core'; +import { getCurrentScope, setCurrentClient } from '@sentry/core/browser'; import { JSDOM } from 'jsdom'; import { TextDecoder, TextEncoder } from 'util'; import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/browser/test/tracing/browserTracingIntegration.test.ts b/packages/browser/test/tracing/browserTracingIntegration.test.ts index 58294ea31fa2..1a9e7da2611d 100644 --- a/packages/browser/test/tracing/browserTracingIntegration.test.ts +++ b/packages/browser/test/tracing/browserTracingIntegration.test.ts @@ -2,7 +2,7 @@ * @vitest-environment jsdom */ -import type { Span, StartSpanOptions } from '@sentry/core'; +import type { Span, StartSpanOptions } from '@sentry/core/browser'; import { getActiveSpan, getCurrentScope, @@ -17,7 +17,7 @@ import { spanToJSON, startInactiveSpan, TRACING_DEFAULTS, -} from '@sentry/core'; +} from '@sentry/core/browser'; import { JSDOM } from 'jsdom'; import { TextDecoder, TextEncoder } from 'util'; import { afterAll, afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/browser/test/tracing/linkedTraces.test.ts b/packages/browser/test/tracing/linkedTraces.test.ts index 56616c6a7692..9426a67dec08 100644 --- a/packages/browser/test/tracing/linkedTraces.test.ts +++ b/packages/browser/test/tracing/linkedTraces.test.ts @@ -1,5 +1,5 @@ -import type { Span } from '@sentry/core'; -import { addChildSpanToSpan, debug, SentrySpan, spanToJSON, timestampInSeconds } from '@sentry/core'; +import type { Span } from '@sentry/core/browser'; +import { addChildSpanToSpan, debug, SentrySpan, spanToJSON, timestampInSeconds } from '@sentry/core/browser'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { BrowserClient } from '../../src'; import type { PreviousTraceInfo } from '../../src/tracing/linkedTraces'; diff --git a/packages/browser/test/tracing/request.test.ts b/packages/browser/test/tracing/request.test.ts index 1674a96d1937..100f1aa9ab30 100644 --- a/packages/browser/test/tracing/request.test.ts +++ b/packages/browser/test/tracing/request.test.ts @@ -1,5 +1,5 @@ -import type { Client } from '@sentry/core'; -import * as utils from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import * as utils from '@sentry/core/browser'; import * as browserUtils from '@sentry-internal/browser-utils'; import type { MockInstance } from 'vitest'; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest'; diff --git a/packages/browser/test/tracing/setActiveSpan.test.ts b/packages/browser/test/tracing/setActiveSpan.test.ts index d3c7ea79cf67..ed9926a01c62 100644 --- a/packages/browser/test/tracing/setActiveSpan.test.ts +++ b/packages/browser/test/tracing/setActiveSpan.test.ts @@ -1,4 +1,4 @@ -import { getActiveSpan, SentrySpan } from '@sentry/core'; +import { getActiveSpan, SentrySpan } from '@sentry/core/browser'; import { describe, expect, it } from 'vitest'; import { setActiveSpanInBrowser } from '../../src'; diff --git a/packages/browser/test/transports/fetch.test.ts b/packages/browser/test/transports/fetch.test.ts index d330fe886d5f..5461bdd9d6f9 100644 --- a/packages/browser/test/transports/fetch.test.ts +++ b/packages/browser/test/transports/fetch.test.ts @@ -1,5 +1,5 @@ -import type { EventEnvelope, EventItem } from '@sentry/core'; -import { createEnvelope, serializeEnvelope } from '@sentry/core'; +import type { EventEnvelope, EventItem } from '@sentry/core/browser'; +import { createEnvelope, serializeEnvelope } from '@sentry/core/browser'; import type { Mock } from 'vitest'; import { afterEach, describe, expect, it, vi } from 'vitest'; import { makeFetchTransport } from '../../src/transports/fetch'; diff --git a/packages/browser/test/transports/offline.test.ts b/packages/browser/test/transports/offline.test.ts index 993d4977ac21..f007c553f1af 100644 --- a/packages/browser/test/transports/offline.test.ts +++ b/packages/browser/test/transports/offline.test.ts @@ -4,8 +4,8 @@ import type { EventItem, InternalBaseTransportOptions, TransportMakeRequestResponse, -} from '@sentry/core'; -import { createEnvelope, createTransport } from '@sentry/core'; +} from '@sentry/core/browser'; +import { createEnvelope, createTransport } from '@sentry/core/browser'; import { TextDecoder, TextEncoder } from 'util'; import { beforeAll, describe, expect, it } from 'vitest'; import { createStore, makeBrowserOfflineTransport, push, shift, unshift } from '../../src/transports/offline'; diff --git a/packages/browser/tsconfig.json b/packages/browser/tsconfig.json index b80e9ddbfaa5..6178eb6a0df8 100644 --- a/packages/browser/tsconfig.json +++ b/packages/browser/tsconfig.json @@ -4,6 +4,8 @@ "include": ["src/**/*", "test/loader.js"], "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", "lib": ["DOM", "es2020", "WebWorker"] } } diff --git a/packages/core/browser.js b/packages/core/browser.js new file mode 100644 index 000000000000..6485bf1fe914 --- /dev/null +++ b/packages/core/browser.js @@ -0,0 +1,3 @@ +// This file is a compatibility shim for bundlers (e.g. webpack 4) that do not +// support the package.json `exports` field for resolving subpath exports. +module.exports = require('./build/cjs/browser.js'); diff --git a/packages/core/package.json b/packages/core/package.json index 47c710cd747f..003ccf76744c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -10,13 +10,35 @@ "node": ">=18" }, "files": [ - "/build" + "/build", + "browser.js", + "server.js" ], "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", + "default": "./build/esm/browser.js" + }, + "require": { + "types": "./build/types/browser.d.ts", + "default": "./build/cjs/browser.js" + } + }, ".": { "import": { "types": "./build/types/index.d.ts", diff --git a/packages/core/rollup.npm.config.mjs b/packages/core/rollup.npm.config.mjs index cc3ad4064820..610de17fadf3 100644 --- a/packages/core/rollup.npm.config.mjs +++ b/packages/core/rollup.npm.config.mjs @@ -14,26 +14,31 @@ if (!packageJson.version) { const packageVersion = packageJson.version; +const settings = { + packageSpecificConfig: { + output: { + // set exports to 'named' or 'auto' so that rollup doesn't warn + exports: 'named', + // set preserveModules to true because we don't want to bundle everything into one file. + preserveModules: + process.env.SENTRY_BUILD_PRESERVE_MODULES === undefined + ? true + : Boolean(process.env.SENTRY_BUILD_PRESERVE_MODULES), + }, + plugins: [ + replace({ + preventAssignment: true, + values: { + __SENTRY_SDK_VERSION__: JSON.stringify(packageVersion), + }, + }), + ], + }, +}; + export default makeNPMConfigVariants( makeBaseNPMConfig({ - packageSpecificConfig: { - output: { - // set exports to 'named' or 'auto' so that rollup doesn't warn - exports: 'named', - // set preserveModules to true because we don't want to bundle everything into one file. - preserveModules: - process.env.SENTRY_BUILD_PRESERVE_MODULES === undefined - ? true - : Boolean(process.env.SENTRY_BUILD_PRESERVE_MODULES), - }, - plugins: [ - replace({ - preventAssignment: true, - values: { - __SENTRY_SDK_VERSION__: JSON.stringify(packageVersion), - }, - }), - ], - }, + ...settings, + entrypoints: ['src/index.ts', 'src/server.ts', 'src/browser.ts'], }), ); diff --git a/packages/core/server.js b/packages/core/server.js new file mode 100644 index 000000000000..cc8162c1c03c --- /dev/null +++ b/packages/core/server.js @@ -0,0 +1,3 @@ +// This file is a compatibility shim for bundlers (e.g. webpack 4) that do not +// support the package.json `exports` field for resolving subpath exports. +module.exports = require('./build/cjs/server.js'); diff --git a/packages/core/src/browser-exports.ts b/packages/core/src/browser-exports.ts new file mode 100644 index 000000000000..97c2fcb48d1f --- /dev/null +++ b/packages/core/src/browser-exports.ts @@ -0,0 +1,20 @@ +// Browser-only: DOM utilities +export { getComponentName, getLocationHref, htmlTreeAsString } from './utils/browser'; + +// Browser-only: feature detection for browser APIs +export { supportsDOMError, supportsHistory, supportsNativeFetch, supportsReportingObserver } from './utils/supports'; + +// Browser-only: XHR and DOM breadcrumb types +export type { XhrBreadcrumbData, XhrBreadcrumbHint } from './types-hoist/breadcrumb'; + +// Browser-only: XHR and DOM handler types +export type { + HandlerDataXhr, + HandlerDataDom, + HandlerDataHistory, + SentryXhrData, + SentryWrappedXMLHttpRequest, +} from './types-hoist/instrument'; + +// Browser-only: replay and profiling options +export type { BrowserClientReplayOptions, BrowserClientProfilingOptions } from './types-hoist/browseroptions'; diff --git a/packages/core/src/browser.ts b/packages/core/src/browser.ts new file mode 100644 index 000000000000..a0ba2b75ef01 --- /dev/null +++ b/packages/core/src/browser.ts @@ -0,0 +1,4 @@ +/* eslint-disable max-lines */ + +export * from './shared-exports'; +export * from './browser-exports'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index c3f8c454e997..dfccfffcf318 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,576 +1,5 @@ /* eslint-disable max-lines */ -export type { ClientClass as SentryCoreCurrentScopes } from './sdk'; -export type { AsyncContextStrategy } from './asyncContext/types'; -export type { Carrier } from './carrier'; -export type { OfflineStore, OfflineTransportOptions } from './transports/offline'; -export type { ServerRuntimeClientOptions } from './server-runtime-client'; -export type { IntegrationIndex } from './integration'; - -export * from './tracing'; -export * from './semanticAttributes'; -export { createEventEnvelope, createSessionEnvelope, createSpanEnvelope } from './envelope'; -export { - captureCheckIn, - withMonitor, - captureException, - captureEvent, - captureMessage, - lastEventId, - close, - flush, - setContext, - setExtra, - setExtras, - setTag, - setTags, - setUser, - setConversationId, - isInitialized, - isEnabled, - startSession, - endSession, - captureSession, - addEventProcessor, -} from './exports'; -export { - getCurrentScope, - getIsolationScope, - getGlobalScope, - withScope, - withIsolationScope, - getClient, - getTraceContextFromScope, - registerExternalPropagationContext, - getExternalPropagationContext, - hasExternalPropagationContext, -} from './currentScopes'; -export { getDefaultCurrentScope, getDefaultIsolationScope } from './defaultScopes'; -export { setAsyncContextStrategy } from './asyncContext'; -export { getGlobalSingleton, getMainCarrier } from './carrier'; -export { makeSession, closeSession, updateSession } from './session'; -export { Scope } from './scope'; -export type { CaptureContext, ScopeContext, ScopeData } from './scope'; -export { notifyEventProcessors } from './eventProcessors'; -export { getEnvelopeEndpointWithUrlEncodedAuth, getReportDialogEndpoint, SENTRY_API_VERSION } from './api'; -export { Client } from './client'; -export { ServerRuntimeClient } from './server-runtime-client'; -export { initAndBind, setCurrentClient } from './sdk'; -export { createTransport } from './transports/base'; -export { makeOfflineTransport } from './transports/offline'; -export { makeMultiplexedTransport, MULTIPLEXED_TRANSPORT_EXTRA_KEY } from './transports/multiplexed'; -export { getIntegrationsToSetup, addIntegration, defineIntegration, installedIntegrations } from './integration'; -export { - _INTERNAL_skipAiProviderWrapping, - _INTERNAL_shouldSkipAiProviderWrapping, - _INTERNAL_clearAiProviderSkips, -} from './utils/ai/providerSkip'; -export { envToBool } from './utils/envToBool'; -export { applyScopeDataToEvent, mergeScopeData, getCombinedScopeData } from './utils/scopeData'; -export { prepareEvent } from './utils/prepareEvent'; -export type { ExclusiveEventHintOrCaptureContext } from './utils/prepareEvent'; -export { createCheckInEnvelope } from './checkin'; -export { hasSpansEnabled } from './utils/hasSpansEnabled'; -export { withStreamedSpan } from './tracing/spans/beforeSendSpan'; -export { isStreamedBeforeSendSpanCallback } from './tracing/spans/beforeSendSpan'; -export { isSentryRequestUrl } from './utils/isSentryRequestUrl'; -export { handleCallbackErrors } from './utils/handleCallbackErrors'; -export { parameterize, fmt } from './utils/parameterize'; -export type { HandleTunnelRequestOptions } from './utils/tunnel'; -export { handleTunnelRequest } from './utils/tunnel'; - -export { addAutoIpAddressToSession } from './utils/ipAddress'; -// eslint-disable-next-line deprecation/deprecation -export { addAutoIpAddressToUser } from './utils/ipAddress'; -export { - convertSpanLinksForEnvelope, - spanToTraceHeader, - spanToJSON, - spanToStreamedSpanJSON, - spanIsSampled, - spanToTraceContext, - getSpanDescendants, - getStatusMessage, - getRootSpan, - INTERNAL_getSegmentSpan, - getActiveSpan, - addChildSpanToSpan, - spanTimeInputToSeconds, - updateSpanName, -} from './utils/spanUtils'; -export { _setSpanForScope as _INTERNAL_setSpanForScope } from './utils/spanOnScope'; -export { parseSampleRate } from './utils/parseSampleRate'; -export { applySdkMetadata } from './utils/sdkMetadata'; -export { getTraceData } from './utils/traceData'; -export { shouldPropagateTraceForUrl } from './utils/tracePropagationTargets'; -export { getTraceMetaTags } from './utils/meta'; -export { debounce } from './utils/debounce'; -export { makeWeakRef, derefWeakRef } from './utils/weakRef'; -export type { MaybeWeakRef } from './utils/weakRef'; -export { shouldIgnoreSpan } from './utils/should-ignore-span'; -export { - winterCGHeadersToDict, - winterCGRequestToRequestData, - httpRequestToRequestData, - extractQueryParamsFromUrl, - headersToDict, - httpHeadersToSpanAttributes, -} from './utils/request'; -export { DEFAULT_ENVIRONMENT, DEV_ENVIRONMENT } from './constants'; -export { addBreadcrumb } from './breadcrumbs'; -export { functionToStringIntegration } from './integrations/functiontostring'; -// eslint-disable-next-line deprecation/deprecation -export { inboundFiltersIntegration } from './integrations/eventFilters'; -export { eventFiltersIntegration } from './integrations/eventFilters'; -export { linkedErrorsIntegration } from './integrations/linkederrors'; -export { moduleMetadataIntegration } from './integrations/moduleMetadata'; -export { requestDataIntegration } from './integrations/requestdata'; -export { captureConsoleIntegration } from './integrations/captureconsole'; -export { patchExpressModule, setupExpressErrorHandler, expressErrorHandler } from './integrations/express/index'; -export type { - ExpressIntegrationOptions, - ExpressHandlerOptions, - ExpressMiddleware, - ExpressErrorMiddleware, -} from './integrations/express/types'; -export { dedupeIntegration } from './integrations/dedupe'; -export { extraErrorDataIntegration } from './integrations/extraerrordata'; -export { rewriteFramesIntegration } from './integrations/rewriteframes'; -export { supabaseIntegration, instrumentSupabaseClient } from './integrations/supabase'; -export { instrumentPostgresJsSql } from './integrations/postgresjs'; -export { zodErrorsIntegration } from './integrations/zoderrors'; -export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter'; -export { consoleIntegration } from './integrations/console'; -export { featureFlagsIntegration, type FeatureFlagsIntegration } from './integrations/featureFlags'; -export { growthbookIntegration } from './integrations/featureFlags'; -export { conversationIdIntegration } from './integrations/conversationId'; - -export { profiler } from './profiling'; -// eslint thinks the entire function is deprecated (while only one overload is actually deprecated) -// Therefore: -// eslint-disable-next-line deprecation/deprecation -export { instrumentFetchRequest, _INTERNAL_getTracingHeadersForFetchRequest } from './fetch'; -export { trpcMiddleware } from './trpc'; -export { wrapMcpServerWithSentry } from './integrations/mcp-server'; -export { captureFeedback } from './feedback'; -export type { ReportDialogOptions } from './report-dialog'; -export { _INTERNAL_captureLog, _INTERNAL_flushLogsBuffer, _INTERNAL_captureSerializedLog } from './logs/internal'; -export * as logger from './logs/public-api'; -export { consoleLoggingIntegration } from './logs/console-integration'; -export { - _INTERNAL_captureMetric, - _INTERNAL_flushMetricsBuffer, - _INTERNAL_captureSerializedMetric, -} from './metrics/internal'; -export * as metrics from './metrics/public-api'; -export type { MetricOptions } from './metrics/public-api'; -export { createConsolaReporter } from './integrations/consola'; -export { addVercelAiProcessors } from './tracing/vercel-ai'; -export { _INTERNAL_getSpanContextForToolCallId, _INTERNAL_cleanupToolCallSpanContext } from './tracing/vercel-ai/utils'; -export { toolCallSpanContextMap as _INTERNAL_toolCallSpanContextMap } from './tracing/vercel-ai/constants'; -export { instrumentOpenAiClient } from './tracing/openai'; -export { OPENAI_INTEGRATION_NAME } from './tracing/openai/constants'; -export { instrumentAnthropicAiClient } from './tracing/anthropic-ai'; -export { ANTHROPIC_AI_INTEGRATION_NAME } from './tracing/anthropic-ai/constants'; -export { instrumentGoogleGenAIClient } from './tracing/google-genai'; -export { GOOGLE_GENAI_INTEGRATION_NAME } from './tracing/google-genai/constants'; -export type { GoogleGenAIResponse } from './tracing/google-genai/types'; -export { createLangChainCallbackHandler, instrumentLangChainEmbeddings } from './tracing/langchain'; -export { LANGCHAIN_INTEGRATION_NAME } from './tracing/langchain/constants'; -export type { LangChainOptions, LangChainIntegration } from './tracing/langchain/types'; -export { instrumentStateGraphCompile, instrumentLangGraph } from './tracing/langgraph'; -export { LANGGRAPH_INTEGRATION_NAME } from './tracing/langgraph/constants'; -export type { LangGraphOptions, LangGraphIntegration, CompiledGraph } from './tracing/langgraph/types'; -export type { OpenAiClient, OpenAiOptions, InstrumentedMethod } from './tracing/openai/types'; -export type { - AnthropicAiClient, - AnthropicAiOptions, - AnthropicAiInstrumentedMethod, - AnthropicAiResponse, -} from './tracing/anthropic-ai/types'; -export type { - GoogleGenAIClient, - GoogleGenAIChat, - GoogleGenAIOptions, - GoogleGenAIInstrumentedMethod, -} from './tracing/google-genai/types'; -// eslint-disable-next-line deprecation/deprecation -export type { GoogleGenAIIstrumentedMethod } from './tracing/google-genai/types'; - -export { SpanBuffer } from './tracing/spans/spanBuffer'; -export { hasSpanStreamingEnabled } from './tracing/spans/hasSpanStreamingEnabled'; -export { spanStreamingIntegration } from './integrations/spanStreaming'; - -export type { FeatureFlag } from './utils/featureFlags'; - -export { - _INTERNAL_copyFlagsFromScopeToEvent, - _INTERNAL_insertFlagToScope, - _INTERNAL_addFeatureFlagToActiveSpan, - _INTERNAL_FLAG_BUFFER_SIZE, - _INTERNAL_MAX_FLAGS_PER_SPAN, -} from './utils/featureFlags'; - -export { applyAggregateErrorsToEvent } from './utils/aggregate-errors'; -export { getBreadcrumbLogLevelFromHttpStatusCode } from './utils/breadcrumb-log-level'; -export { getComponentName, getLocationHref, htmlTreeAsString } from './utils/browser'; -export { dsnFromString, dsnToString, makeDsn } from './utils/dsn'; -// eslint-disable-next-line deprecation/deprecation -export { SentryError } from './utils/error'; -export { GLOBAL_OBJ } from './utils/worldwide'; -export type { InternalGlobal } from './utils/worldwide'; -export { addConsoleInstrumentationHandler } from './instrument/console'; -export { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler } from './instrument/fetch'; -export { addGlobalErrorInstrumentationHandler } from './instrument/globalError'; -export { addGlobalUnhandledRejectionInstrumentationHandler } from './instrument/globalUnhandledRejection'; -export { addHandler, maybeInstrument, resetInstrumentationHandlers, triggerHandlers } from './instrument/handlers'; -export { - isDOMError, - isDOMException, - isElement, - isError, - isErrorEvent, - isEvent, - isInstanceOf, - isParameterizedString, - isPlainObject, - isPrimitive, - isRegExp, - isString, - isSyntheticEvent, - isThenable, - isVueViewModel, -} from './utils/is'; -export { isBrowser } from './utils/isBrowser'; -export { CONSOLE_LEVELS, consoleSandbox, debug, originalConsoleMethods } from './utils/debug-logger'; -export type { SentryDebugLogger } from './utils/debug-logger'; -export { - addContextToFrame, - addExceptionMechanism, - addExceptionTypeValue, - checkOrSetAlreadyCaught, - isAlreadyCaptured, - getEventDescription, - parseSemver, - uuid4, -} from './utils/misc'; -export { isNodeEnv, loadModule } from './utils/node'; -export { normalize, normalizeToSize, normalizeUrlToBase } from './utils/normalize'; -export { - addNonEnumerableProperty, - convertToPlainObject, - // eslint-disable-next-line deprecation/deprecation - dropUndefinedKeys, - extractExceptionKeysForMessage, - fill, - getOriginalFunction, - markFunctionWrapped, - objectify, -} from './utils/object'; -export { basename, dirname, isAbsolute, join, normalizePath, relative, resolve } from './utils/path'; -export { makePromiseBuffer, SENTRY_BUFFER_FULL_ERROR } from './utils/promisebuffer'; -export type { PromiseBuffer } from './utils/promisebuffer'; -export { severityLevelFromString } from './utils/severity'; -export { replaceExports } from './utils/exports'; -export { - UNKNOWN_FUNCTION, - createStackParser, - getFramesFromEvent, - getFunctionName, - stackParserFromStackParserOptions, - stripSentryFramesAndReverse, -} from './utils/stacktrace'; -export { filenameIsInApp, node, nodeStackLineParser } from './utils/node-stack-trace'; -export { isMatchingPattern, safeJoin, snipLine, stringMatchesSomePattern, truncate } from './utils/string'; -export { - isNativeFunction, - supportsDOMError, - supportsDOMException, - supportsErrorEvent, - // eslint-disable-next-line deprecation/deprecation - supportsFetch, - supportsHistory, - supportsNativeFetch, - // eslint-disable-next-line deprecation/deprecation - supportsReferrerPolicy, - supportsReportingObserver, -} from './utils/supports'; -export { SyncPromise, rejectedSyncPromise, resolvedSyncPromise } from './utils/syncpromise'; -export { browserPerformanceTimeOrigin, dateTimestampInSeconds, timestampInSeconds } from './utils/time'; -export { - TRACEPARENT_REGEXP, - extractTraceparentData, - generateSentryTraceHeader, - propagationContextFromHeaders, - shouldContinueTrace, - generateTraceparentHeader, -} from './utils/tracing'; -export { getSDKSource, isBrowserBundle } from './utils/env'; -export type { SdkSource } from './utils/env'; -export { - addItemToEnvelope, - createAttachmentEnvelopeItem, - createEnvelope, - createEventEnvelopeHeaders, - createSpanEnvelopeItem, - envelopeContainsItemType, - envelopeItemTypeToDataCategory, - forEachEnvelopeItem, - getSdkMetadataForEnvelopeHeader, - parseEnvelope, - serializeEnvelope, -} from './utils/envelope'; -export { createClientReportEnvelope } from './utils/clientreport'; -export { - DEFAULT_RETRY_AFTER, - disabledUntil, - isRateLimited, - parseRetryAfterHeader, - updateRateLimits, -} from './utils/ratelimit'; -export type { RateLimits } from './utils/ratelimit'; -export { - MAX_BAGGAGE_STRING_LENGTH, - SENTRY_BAGGAGE_KEY_PREFIX, - SENTRY_BAGGAGE_KEY_PREFIX_REGEX, - baggageHeaderToDynamicSamplingContext, - dynamicSamplingContextToSentryBaggageHeader, - parseBaggageHeader, - objectToBaggageHeader, -} from './utils/baggage'; -export { - getSanitizedUrlString, - parseUrl, - stripUrlQueryAndFragment, - parseStringToURLObject, - getHttpSpanDetailsFromUrlObject, - isURLObjectRelative, - getSanitizedUrlStringFromUrlObject, - stripDataUrlContent, -} from './utils/url'; -export { - eventFromMessage, - eventFromUnknownInput, - exceptionFromError, - parseStackFrames, - _enhanceErrorWithSentryInfo as _INTERNAL_enhanceErrorWithSentryInfo, -} from './utils/eventbuilder'; -export { callFrameToStackFrame, watchdogTimer } from './utils/anr'; -export { LRUMap } from './utils/lru'; -export { generateTraceId, generateSpanId } from './utils/propagationContext'; -export { vercelWaitUntil } from './utils/vercelWaitUntil'; -export { flushIfServerless } from './utils/flushIfServerless'; -export { SDK_VERSION } from './utils/version'; -export { getDebugImagesForResources, getFilenameToDebugIdMap } from './utils/debug-ids'; -export { getFilenameToMetadataMap } from './metadata'; -export { escapeStringForRegex } from './vendor/escapeStringForRegex'; - -export type { Attachment } from './types-hoist/attachment'; -export type { - Breadcrumb, - BreadcrumbHint, - FetchBreadcrumbData, - XhrBreadcrumbData, - FetchBreadcrumbHint, - XhrBreadcrumbHint, -} from './types-hoist/breadcrumb'; -export type { ClientReport, Outcome, EventDropReason } from './types-hoist/clientreport'; -export type { - Context, - Contexts, - DeviceContext, - OsContext, - AppContext, - CultureContext, - TraceContext, - CloudResourceContext, - MissingInstrumentationContext, -} from './types-hoist/context'; -export type { DataCategory } from './types-hoist/datacategory'; -export type { DsnComponents, DsnLike, DsnProtocol } from './types-hoist/dsn'; -export type { DebugImage, DebugMeta } from './types-hoist/debugMeta'; -export type { - AttachmentItem, - BaseEnvelopeHeaders, - BaseEnvelopeItemHeaders, - ClientReportEnvelope, - ClientReportItem, - DynamicSamplingContext, - Envelope, - EnvelopeItemType, - EnvelopeItem, - EventEnvelope, - EventEnvelopeHeaders, - EventItem, - ReplayEnvelope, - FeedbackItem, - SessionEnvelope, - SessionItem, - UserFeedbackItem, - CheckInItem, - CheckInEnvelope, - RawSecurityEnvelope, - RawSecurityItem, - ProfileItem, - ProfileChunkEnvelope, - ProfileChunkItem, - SpanEnvelope, - StreamedSpanEnvelope, - SpanItem, - LogEnvelope, - MetricEnvelope, -} from './types-hoist/envelope'; -export type { ExtendedError } from './types-hoist/error'; -export type { Event, EventHint, EventType, ErrorEvent, TransactionEvent } from './types-hoist/event'; -export type { EventProcessor } from './types-hoist/eventprocessor'; -export type { Exception } from './types-hoist/exception'; -export type { Extra, Extras } from './types-hoist/extra'; -export type { Integration, IntegrationFn } from './types-hoist/integration'; -export type { Mechanism } from './types-hoist/mechanism'; -export type { ExtractedNodeRequestData, HttpHeaderValue, Primitive, WorkerLocation } from './types-hoist/misc'; -export type { ClientOptions, CoreOptions as Options, ServerRuntimeOptions } from './types-hoist/options'; -export type { Package } from './types-hoist/package'; -export type { PolymorphicEvent, PolymorphicRequest } from './types-hoist/polymorphics'; -export type { - ThreadId, - FrameId, - StackId, - ThreadCpuSample, - ThreadCpuStack, - ThreadCpuFrame, - ThreadCpuProfile, - ContinuousThreadCpuProfile, - Profile, - ProfileChunk, -} from './types-hoist/profiling'; -export type { - ReplayEndEvent, - ReplayEvent, - ReplayRecordingData, - ReplayRecordingMode, - ReplayStartEvent, - ReplayStopReason, -} from './types-hoist/replay'; -export type { - FeedbackEvent, - FeedbackFormData, - FeedbackInternalOptions, - FeedbackModalIntegration, - FeedbackScreenshotIntegration, - SendFeedback, - SendFeedbackParams, - UserFeedback, -} from './types-hoist/feedback'; -export type { - QueryParams, - RequestEventData, - RequestHookInfo, - ResponseHookInfo, - SanitizedRequestData, -} from './types-hoist/request'; -export type { Runtime } from './types-hoist/runtime'; -export type { SdkInfo } from './types-hoist/sdkinfo'; -export type { SdkMetadata } from './types-hoist/sdkmetadata'; -export type { - SessionAggregates, - AggregationCounts, - Session, - SessionContext, - SessionStatus, - SerializedSession, -} from './types-hoist/session'; -export type { SeverityLevel } from './types-hoist/severity'; -export type { - Span, - SentrySpanArguments, - SpanOrigin, - SpanAttributeValue, - SpanAttributes, - SpanTimeInput, - SpanJSON, - SpanContextData, - TraceFlag, - SerializedStreamedSpan, - SerializedStreamedSpanContainer, - StreamedSpanJSON, -} from './types-hoist/span'; -export type { SpanStatus } from './types-hoist/spanStatus'; -export type { Log, LogSeverityLevel } from './types-hoist/log'; -export type { SpanLink } from './types-hoist/link'; -export type { - Metric, - MetricType, - SerializedMetric, - SerializedMetricContainer, - // eslint-disable-next-line deprecation/deprecation - SerializedMetricAttributeValue, -} from './types-hoist/metric'; -export type { TimedEvent } from './types-hoist/timedEvent'; -export type { StackFrame } from './types-hoist/stackframe'; -export type { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from './types-hoist/stacktrace'; -export type { PropagationContext, TracePropagationTargets, SerializedTraceData } from './types-hoist/tracing'; -export type { StartSpanOptions } from './types-hoist/startSpanOptions'; -export type { TraceparentData, TransactionSource } from './types-hoist/transaction'; -export type { - TracesSamplerSamplingContext, - CustomSamplingContext, - SamplingContext, -} from './types-hoist/samplingcontext'; -export type { - DurationUnit, - InformationUnit, - FractionUnit, - MeasurementUnit, - NoneUnit, - Measurements, -} from './types-hoist/measurement'; -export type { Thread } from './types-hoist/thread'; -export type { - Transport, - TransportRequest, - TransportMakeRequestResponse, - InternalBaseTransportOptions, - BaseTransportOptions, - TransportRequestExecutor, -} from './types-hoist/transport'; -export type { User } from './types-hoist/user'; -export type { WebFetchHeaders, WebFetchRequest } from './types-hoist/webfetchapi'; -export type { WrappedFunction } from './types-hoist/wrappedfunction'; -export type { - HandlerDataFetch, - HandlerDataXhr, - HandlerDataDom, - HandlerDataConsole, - HandlerDataHistory, - HandlerDataError, - HandlerDataUnhandledRejection, - ConsoleLevel, - SentryXhrData, - SentryWrappedXMLHttpRequest, -} from './types-hoist/instrument'; -export type { BrowserClientReplayOptions, BrowserClientProfilingOptions } from './types-hoist/browseroptions'; -export type { - CheckIn, - MonitorConfig, - FinishedCheckIn, - InProgressCheckIn, - SerializedCheckIn, -} from './types-hoist/checkin'; -export type { ParameterizedString } from './types-hoist/parameterize'; -export type { ContinuousProfiler, ProfilingIntegration, Profiler } from './types-hoist/profiling'; -export type { ViewHierarchyData, ViewHierarchyWindow } from './types-hoist/view-hierarchy'; -export type { LegacyCSPReport } from './types-hoist/csp'; -export type { SerializedLog, SerializedLogContainer } from './types-hoist/log'; -export type { - BuildTimeOptionsBase, - UnstableVitePluginOptions, - UnstableRollupPluginOptions, - UnstableWebpackPluginOptions, -} from './build-time-plugins/buildTimeOptionsBase'; -export { - withRandomSafeContext as _INTERNAL_withRandomSafeContext, - type RandomSafeContextRunner as _INTERNAL_RandomSafeContextRunner, - safeMathRandom as _INTERNAL_safeMathRandom, - safeDateNow as _INTERNAL_safeDateNow, -} from './utils/randomSafeContext'; -export { safeUnref as _INTERNAL_safeUnref } from './utils/timer'; +export * from './shared-exports'; +export * from './server-exports'; +export * from './browser-exports'; diff --git a/packages/core/src/integrations/express/index.ts b/packages/core/src/integrations/express/index.ts index bbb1f8fe8a28..df616e7b7f32 100644 --- a/packages/core/src/integrations/express/index.ts +++ b/packages/core/src/integrations/express/index.ts @@ -33,7 +33,6 @@ import { DEBUG_BUILD } from '../../debug-build'; import type { ExpressApplication, ExpressErrorMiddleware, - ExpressExport, ExpressHandlerOptions, ExpressIntegrationOptions, ExpressLayer, @@ -49,16 +48,13 @@ import type { import { defaultShouldHandleError, getLayerPath, - hasDefaultProp, isExpressWithoutRouterPrototype, isExpressWithRouterPrototype, } from './utils'; import { wrapMethod } from '../../utils/object'; import { patchLayer } from './patch-layer'; import { setSDKProcessingMetadata } from './set-sdk-processing-metadata'; - -const getExpressExport = (express: ExpressModuleExport): ExpressExport => - hasDefaultProp(express) ? express.default : (express as ExpressExport); +import { getDefaultExport } from '../../utils/get-default-export'; function isLegacyOptions( options: ExpressModuleExport | (ExpressIntegrationOptions & { express: ExpressModuleExport }), @@ -119,7 +115,7 @@ export function patchExpressModule( } // pass in the require() or import() result of express - const express = getExpressExport(moduleExports); + const express = getDefaultExport(moduleExports); const routerProto: ExpressRouterv4 | ExpressRouterv5 | undefined = isExpressWithRouterPrototype(express) ? express.Router.prototype // Express v5 : isExpressWithoutRouterPrototype(express) diff --git a/packages/core/src/integrations/express/utils.ts b/packages/core/src/integrations/express/utils.ts index c3473bbab18a..af22a6ea1d97 100644 --- a/packages/core/src/integrations/express/utils.ts +++ b/packages/core/src/integrations/express/utils.ts @@ -30,7 +30,6 @@ import type { SpanAttributes } from '../../types-hoist/span'; import { getStoredLayers } from './request-layer-store'; import type { - ExpressExport, ExpressIntegrationOptions, ExpressLayer, ExpressLayerType, @@ -254,14 +253,6 @@ const isExpressRouterPrototype = (routerProto?: unknown): routerProto is Express export const isExpressWithoutRouterPrototype = (express: unknown): express is ExpressExportv4 => isExpressRouterPrototype((express as ExpressExportv4).Router) && !isExpressWithRouterPrototype(express); -// dynamic puts the default on .default, require or normal import are fine -export const hasDefaultProp = ( - express: unknown, -): express is { - [k: string]: unknown; - default: ExpressExport; -} => !!express && typeof express === 'object' && 'default' in express && typeof express.default === 'function'; - function getStatusCodeFromResponse(error: MiddlewareError): number { const statusCode = error.status || error.statusCode || error.status_code || error.output?.statusCode; return statusCode ? parseInt(statusCode as string, 10) : 500; diff --git a/packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts b/packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts new file mode 100644 index 000000000000..7ccf029021c0 --- /dev/null +++ b/packages/core/src/integrations/http/add-outgoing-request-breadcrumb.ts @@ -0,0 +1,39 @@ +import { addBreadcrumb } from '../../breadcrumbs'; +import { getBreadcrumbLogLevelFromHttpStatusCode } from '../../utils/breadcrumb-log-level'; +import { getSanitizedUrlString, parseUrl } from '../../utils/url'; +import { getRequestUrl } from './get-request-url'; +import type { HttpClientRequest, HttpIncomingMessage } from './types'; + +/** + * Create a breadcrumb for a finished outgoing HTTP request. + */ +export function addOutgoingRequestBreadcrumb( + request: HttpClientRequest, + response: HttpIncomingMessage | undefined, +): void { + const url = getRequestUrl(request); + const parsedUrl = parseUrl(url); + + const statusCode = response?.statusCode; + const level = getBreadcrumbLogLevelFromHttpStatusCode(statusCode); + + addBreadcrumb( + { + category: 'http', + data: { + status_code: statusCode, + url: getSanitizedUrlString(parsedUrl), + 'http.method': request.method || 'GET', + ...(parsedUrl.search ? { 'http.query': parsedUrl.search } : {}), + ...(parsedUrl.hash ? { 'http.fragment': parsedUrl.hash } : {}), + }, + type: 'http', + level, + }, + { + event: 'response', + request, + response, + }, + ); +} diff --git a/packages/core/src/integrations/http/client-patch.ts b/packages/core/src/integrations/http/client-patch.ts new file mode 100644 index 000000000000..a8f4e858286b --- /dev/null +++ b/packages/core/src/integrations/http/client-patch.ts @@ -0,0 +1,127 @@ +/** + * Platform-portable HTTP(S) outgoing-request patching integration + * + * Patches the `http` and `https` Node.js built-in module exports to create + * Sentry spans for outgoing requests and optionally inject distributed trace + * propagation headers. + * + * @module + * + * This Sentry integration is a derivative work based on the OpenTelemetry + * HTTP instrumentation. + * + * + * + * Extended under the terms of the Apache 2.0 license linked below: + * + * ---- + * + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * 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 type { WrappedFunction } from '../../types-hoist/wrappedfunction'; +import { getHttpClientSubscriptions } from './client-subscriptions'; + +function patchHttpRequest( + httpModule: HttpExport, + options: HttpInstrumentationOptions, + protocol: 'http:' | 'https:', + port: 80 | 443, +): WrappedFunction { + // avoid double-wrap + if (!getOriginalFunction(httpModule.request)) { + const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = getHttpClientSubscriptions(options); + + const originalRequest = httpModule.request; + wrapMethod(httpModule, 'request', function patchedRequest(this: HttpExport, ...args: unknown[]) { + // Apply protocol defaults when options are passed as a plain object + if (args.length > 0 && typeof args[0] === 'object' && args[0] !== null) { + const opts = args[0] as Record; + if ((opts.constructor as { name?: string } | undefined)?.name !== 'URL') { + args[0] = { protocol, port, ...opts }; + } + } + const request = originalRequest.apply(this, args) as HttpClientRequest; + onHttpClientRequestCreated({ request }, HTTP_ON_CLIENT_REQUEST); + return request; + }); + } + + return httpModule.request; +} + +function patchHttpGet(httpModule: HttpExport, patchedRequest: WrappedFunction) { + if (!getOriginalFunction(httpModule.get)) { + wrapMethod(httpModule, 'get', function patchedGet(this: HttpExport, ...args: unknown[]) { + // http.get is like http.request but automatically calls .end() + const request = patchedRequest.apply(this, args) as HttpClientRequest; + request.end(); + return request; + }); + } +} + +function patchModule( + httpModuleExport: HttpModuleExport, + options: HttpInstrumentationOptions = {}, + protocol: 'http:' | 'https:', + port: 80 | 443, +): HttpModuleExport { + const httpDefault = getDefaultExport(httpModuleExport); + const httpModule = httpModuleExport as HttpExport; + // if we have a default, patch that, and copy to the import container + if (httpDefault !== httpModuleExport) { + patchModule(httpDefault, options, protocol, port); + // copy with defineProperty because these might be configured oddly + for (const method of ['get', 'request']) { + const desc = Object.getOwnPropertyDescriptor(httpDefault, method); + /* v8 ignore next - will always be set at this point */ + Object.defineProperty(httpModule, method, desc ?? {}); + } + return httpModule; + } + + patchHttpGet(httpModule, patchHttpRequest(httpModule, options, protocol, port)); + return httpModuleExport; +} + +/** + * Patch an `http`-module-shaped export so that every outgoing request is + * tracked as a Sentry span. + * + * @example + * ```javascript + * import http from 'node:http'; + * import { patchHttpModule } from '@sentry/core'; + * patchHttpModule(http, { propagateTrace: true }); + * ``` + */ +export const patchHttpModuleClient = ( + httpModuleExport: HttpModuleExport, + options: HttpInstrumentationOptions = {}, +): HttpModuleExport => patchModule(httpModuleExport, options, 'http:', 80); + +/** + * Patch an `https`-module-shaped export. Equivalent to `patchHttpModule` but + * sets default `protocol` / `port` for HTTPS when option objects are passed. + */ +export const patchHttpsModuleClient = ( + httpModuleExport: HttpModuleExport, + options: HttpInstrumentationOptions = {}, +): HttpModuleExport => patchModule(httpModuleExport, options, 'https:', 443); diff --git a/packages/core/src/integrations/http/client-subscriptions.ts b/packages/core/src/integrations/http/client-subscriptions.ts new file mode 100644 index 000000000000..6417e8364905 --- /dev/null +++ b/packages/core/src/integrations/http/client-subscriptions.ts @@ -0,0 +1,165 @@ +/** + * Define the channels and subscription methods to subscribe to in order to + * instrument the `node:http` module. Note that this does *not* actually + * register the subscriptions, it simply returns a data object with the + * channel names and the subscription handlers. Attach these to diagnostic + * channels on Node versions where they are supported (ie, >=22.12.0). + * + * If any other platforms that do support diagnostic channels eventually add + * channel coverage for the `node:http` client, then these methods can be + * used on those platforms as well. + * + * This implementation is used in the client-patch strategy, by simply + * calling the handlers with the relevant data at the appropriate time. + */ + +import type { SpanStatus } from '../../types-hoist/spanStatus'; +import { addOutgoingRequestBreadcrumb } from './add-outgoing-request-breadcrumb'; +import { + getSpanStatusFromHttpCode, + SPAN_STATUS_ERROR, + SPAN_STATUS_UNSET, + startInactiveSpan, + SUPPRESS_TRACING_KEY, + withActiveSpan, +} from '../../tracing'; +import { debug } from '../../utils/debug-logger'; +import { LRUMap } from '../../utils/lru'; +import { getOutgoingRequestSpanData, setIncomingResponseSpanData } from './get-outgoing-span-data'; +import { getRequestUrl } from './get-request-url'; +import { injectTracePropagationHeaders } from './inject-trace-propagation-headers'; +import type { HttpInstrumentationOptions, HttpClientRequest } from './types'; +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'; + +type ChannelListener = (message: unknown, name: string | symbol) => void; + +export type HttpClientSubscriptions = Record; + +export function getHttpClientSubscriptions(options: HttpInstrumentationOptions): HttpClientSubscriptions { + const propagationDecisionMap = new LRUMap(100); + const getConfig = () => getClient()?.getOptions(); + + const onHttpClientRequestCreated: ChannelListener = (data: unknown): void => { + const clientOptions = getConfig(); + const { + errorMonitor = 'error', + spans: createSpans = clientOptions ? hasSpansEnabled(clientOptions) : true, + propagateTrace = false, + breadcrumbs = true, + } = options; + + const { request } = data as { request: HttpClientRequest }; + + // Skip if tracing is suppressed (e.g., inside Sentry.suppressTracing()) + if (getCurrentScope().getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY] === true) { + return; + } + + // check if request is ignored anyway + if (options.ignoreOutgoingRequests?.(getRequestUrl(request), request)) { + return; + } + + if (!createSpans) { + // Even without spans, set up a response listener for breadcrumbs. + if (breadcrumbs) { + const onRequestError = () => { + addOutgoingRequestBreadcrumb(request, undefined); + }; + request.on(errorMonitor, onRequestError); + request.prependListener('response', response => { + // no longer need this, got a response. + request.removeListener(errorMonitor, onRequestError); + if (request.listenerCount('response') <= 1) { + response.resume(); + } + response.on('end', () => addOutgoingRequestBreadcrumb(request, response)); + response.on(errorMonitor, () => addOutgoingRequestBreadcrumb(request, undefined)); + }); + } + + if (propagateTrace) { + injectTracePropagationHeaders(request, propagationDecisionMap); + } + return; + } + + const span = startInactiveSpan(getOutgoingRequestSpanData(request)); + options.outgoingRequestHook?.(span, request); + + // Inject trace headers after span creation so sentry-trace contains the outgoing + // span's ID (not the parent's), enabling downstream services to link to this span. + if (propagateTrace) { + if (span.isRecording()) { + withActiveSpan(span, () => { + injectTracePropagationHeaders(request, propagationDecisionMap); + }); + } else { + injectTracePropagationHeaders(request, propagationDecisionMap); + } + } + + let spanEnded = false; + function endSpan(status: SpanStatus): void { + if (!spanEnded) { + spanEnded = true; + span.setStatus(status); + span.end(); + } + } + + // Fallback: end span if the connection closes before any response. + const requestOnClose = () => endSpan({ code: SPAN_STATUS_UNSET }); + request.on('close', requestOnClose); + + request.on(errorMonitor, error => { + DEBUG_BUILD && debug.log(LOG_PREFIX, 'outgoingRequest on request error()', error); + if (breadcrumbs) { + addOutgoingRequestBreadcrumb(request, undefined); + } + endSpan({ code: SPAN_STATUS_ERROR }); + }); + + request.prependListener('response', response => { + // no longer need this, listen on response now + request.removeListener('close', requestOnClose); + if (request.listenerCount('response') <= 1) { + response.resume(); + } + setIncomingResponseSpanData(response, span); + options.outgoingResponseHook?.(span, response); + + let finished = false; + function finishWithResponse(error?: unknown): void { + if (finished) { + return; + } + finished = true; + if (error) { + DEBUG_BUILD && debug.log(LOG_PREFIX, 'outgoingRequest on response error()', error); + } + if (breadcrumbs) { + addOutgoingRequestBreadcrumb(request, response); + } + const aborted = response.aborted && !response.complete; + const status: SpanStatus = + error || typeof response.statusCode !== 'number' || aborted + ? { code: SPAN_STATUS_ERROR } + : getSpanStatusFromHttpCode(response.statusCode); + options.applyCustomAttributesOnSpan?.(span, request, response); + endSpan(status); + } + + response.on('end', finishWithResponse); + response.on(errorMonitor, finishWithResponse); + }); + }; + + return { + [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated, + }; +} diff --git a/packages/core/src/integrations/http/constants.ts b/packages/core/src/integrations/http/constants.ts new file mode 100644 index 000000000000..f2af12b00b62 --- /dev/null +++ b/packages/core/src/integrations/http/constants.ts @@ -0,0 +1,5 @@ +export const LOG_PREFIX = '@sentry/instrumentation-http'; +export const HTTP_ON_CLIENT_REQUEST = 'http.client.request.created'; +export const HTTP_ON_SERVER_REQUEST = 'http.server.request.start'; +export type ClientSubscriptionName = typeof HTTP_ON_CLIENT_REQUEST; +export type ServerSubscriptionName = typeof HTTP_ON_SERVER_REQUEST; diff --git a/packages/core/src/integrations/http/get-outgoing-span-data.ts b/packages/core/src/integrations/http/get-outgoing-span-data.ts new file mode 100644 index 000000000000..e8334a0981b3 --- /dev/null +++ b/packages/core/src/integrations/http/get-outgoing-span-data.ts @@ -0,0 +1,85 @@ +import type { Span, SpanAttributes } from '../../types-hoist/span'; +import { SEMANTIC_ATTRIBUTE_SENTRY_OP } from '../../semanticAttributes'; +import { getHttpSpanDetailsFromUrlObject, parseStringToURLObject } from '../../utils/url'; +import type { HttpClientRequest, HttpIncomingMessage } from './types'; +import { getRequestUrl } from './get-request-url'; +import type { StartSpanOptions } from '../../types-hoist/startSpanOptions'; + +/** + * Build the initial span name and attributes for an outgoing HTTP request. + * This is called before the span is created, to get the initial details. + */ +export function getOutgoingRequestSpanData(request: HttpClientRequest): StartSpanOptions { + const url = getRequestUrl(request); + const [name, attributes] = getHttpSpanDetailsFromUrlObject( + parseStringToURLObject(url), + 'client', + 'auto.http.client', + request, + ); + + const userAgent = request.getHeader('user-agent'); + + return { + name, + attributes: { + // TODO(v11): Update these to the Sentry semantic attributes for urls. + // https://getsentry.github.io/sentry-conventions/attributes/ + [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', + 'otel.kind': 'CLIENT', + 'http.url': url, + 'http.method': request.method, + 'http.target': request.path || '/', + 'net.peer.name': request.host, + 'http.host': request.getHeader('host') as string | undefined, + ...(userAgent ? { 'user_agent.original': userAgent as string } : {}), + ...attributes, + }, + onlyIfParent: true, + }; +} + +/** + * Add span attributes once the response is received. + */ +export function setIncomingResponseSpanData(response: HttpIncomingMessage, span: Span): void { + const { statusCode, statusMessage, httpVersion, socket } = response; + const transport = httpVersion?.toUpperCase() !== 'QUIC' ? 'ip_tcp' : 'ip_udp'; + + span.setAttributes({ + 'http.response.status_code': statusCode, + 'network.protocol.version': httpVersion, + // TODO(v11): Update these to the Sentry semantic attributes for urls. + // https://getsentry.github.io/sentry-conventions/attributes/ + 'http.flavor': httpVersion, + 'network.transport': transport, + 'net.transport': transport, + 'http.status_text': statusMessage?.toUpperCase(), + 'http.status_code': statusCode, + ...getResponseContentLengthAttributes(response), + ...getSocketAttrs(socket), + }); +} + +function getSocketAttrs(socket: HttpIncomingMessage['socket']): SpanAttributes { + if (!socket) return {}; + const { remoteAddress, remotePort } = socket; + return { + 'network.peer.address': remoteAddress, + 'network.peer.port': remotePort, + 'net.peer.ip': remoteAddress, + 'net.peer.port': remotePort, + }; +} + +function getResponseContentLengthAttributes(response: HttpIncomingMessage): SpanAttributes { + const { headers } = response; + const contentLengthHeader = headers['content-length']; + const length = contentLengthHeader ? parseInt(String(contentLengthHeader), 10) : -1; + const encoding = headers['content-encoding']; + return length >= 0 + ? encoding && encoding !== 'identity' + ? { 'http.response_content_length': length } + : { 'http.response_content_length_uncompressed': length } + : {}; +} diff --git a/packages/core/src/integrations/http/get-request-url.ts b/packages/core/src/integrations/http/get-request-url.ts new file mode 100644 index 000000000000..773c4303b202 --- /dev/null +++ b/packages/core/src/integrations/http/get-request-url.ts @@ -0,0 +1,12 @@ +import type { HttpClientRequest } from './types'; + +/** + * Build the full URL string from a Node.js ClientRequest. + * Mirrors the `getClientRequestUrl` helper in node-core. + */ +export function getRequestUrl(request: HttpClientRequest): string { + const hostname = request.getHeader('host') || request.host; + const protocol = request.protocol ?? 'http:'; + const path = request.path ?? '/'; + return `${protocol}//${hostname}${path}`; +} diff --git a/packages/core/src/integrations/http/index.ts b/packages/core/src/integrations/http/index.ts new file mode 100644 index 000000000000..bbcaf3400c07 --- /dev/null +++ b/packages/core/src/integrations/http/index.ts @@ -0,0 +1,3 @@ +export type { HttpInstrumentationOptions } from './types'; +export * from './client-patch'; +export * from './client-subscriptions'; diff --git a/packages/core/src/integrations/http/inject-trace-propagation-headers.ts b/packages/core/src/integrations/http/inject-trace-propagation-headers.ts new file mode 100644 index 000000000000..656ffa0d3250 --- /dev/null +++ b/packages/core/src/integrations/http/inject-trace-propagation-headers.ts @@ -0,0 +1,66 @@ +import type { LRUMap } from '../../utils/lru'; +import { getClient } from '../../currentScopes'; +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 { LOG_PREFIX } from './constants'; +import { getRequestUrl } from './get-request-url'; +import { mergeBaggage } from './merge-baggage'; +import type { HttpClientRequest } from './types'; + +/** + * Inject Sentry trace-propagation headers into an outgoing request if the + * target URL matches the configured `tracePropagationTargets`. + */ +export function injectTracePropagationHeaders( + request: HttpClientRequest, + propagationDecisionMap: LRUMap, +): void { + const url = getRequestUrl(request); + const clientOptions = getClient()?.getOptions(); + const { tracePropagationTargets, propagateTraceparent } = clientOptions ?? {}; + + if (!shouldPropagateTraceForUrl(url, tracePropagationTargets, propagationDecisionMap)) { + return; + } + + const traceData = getTraceData({ propagateTraceparent }); + if (!traceData) return; + + const { 'sentry-trace': sentryTrace, baggage, traceparent } = traceData; + + if (sentryTrace && !request.getHeader('sentry-trace')) { + try { + request.setHeader('sentry-trace', sentryTrace); + DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added sentry-trace header'); + } catch (e) { + DEBUG_BUILD && + debug.error(LOG_PREFIX, 'Failed to set sentry-trace header:', isError(e) ? e.message : 'Unknown error'); + } + } + + if (traceparent && !request.getHeader('traceparent')) { + try { + request.setHeader('traceparent', traceparent); + DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added traceparent header'); + } catch (e) { + DEBUG_BUILD && + debug.error(LOG_PREFIX, 'Failed to set traceparent header:', isError(e) ? e.message : 'Unknown error'); + } + } + + if (baggage) { + const merged = mergeBaggage(request.getHeader('baggage'), baggage); + if (merged) { + try { + request.setHeader('baggage', merged); + DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added baggage header'); + } catch (e) { + DEBUG_BUILD && + debug.error(LOG_PREFIX, 'Failed to set baggage header:', isError(e) ? e.message : 'Unknown error'); + } + } + } +} diff --git a/packages/core/src/integrations/http/merge-baggage.ts b/packages/core/src/integrations/http/merge-baggage.ts new file mode 100644 index 000000000000..46eaf50f01c1 --- /dev/null +++ b/packages/core/src/integrations/http/merge-baggage.ts @@ -0,0 +1,28 @@ +import { objectToBaggageHeader, parseBaggageHeader } from '../../utils/baggage'; + +// TODO: should this be in utils/baggage? + +/** + * Merge two baggage header values, preserving non-Sentry entries from the + * existing header and overwriting Sentry entries with new ones. + */ +export function mergeBaggage(existing: string | string[] | number | undefined, incoming: string): string | undefined { + if (!existing) return incoming; + + const existingEntries = parseBaggageHeader(existing) ?? {}; + const incomingEntries = parseBaggageHeader(incoming) ?? {}; + + // Start with non-sentry entries from existing (sentry-* entries will be replaced by incoming) + const merged: Record = {}; + for (const [key, value] of Object.entries(existingEntries)) { + if (!key.startsWith('sentry-')) { + merged[key] = value; + } + } + // Add all incoming entries (the new Sentry DSC) + for (const [key, value] of Object.entries(incomingEntries)) { + merged[key] = value; + } + + return objectToBaggageHeader(merged); +} diff --git a/packages/core/src/integrations/http/types.ts b/packages/core/src/integrations/http/types.ts new file mode 100644 index 000000000000..0347b056268b --- /dev/null +++ b/packages/core/src/integrations/http/types.ts @@ -0,0 +1,247 @@ +/** + * Platform-portable HTTP(S) outgoing-request integration – type definitions. + * + * @module + * + * This Sentry integration is a derivative work based on the OpenTelemetry + * HTTP instrumentation. + * + * + * + * Extended under the terms of the Apache 2.0 license linked below: + * + * ---- + * + * Copyright The OpenTelemetry Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import type { RequestEventData } from '../../types-hoist/request'; +import type { Span } from '../../types-hoist/span'; + +/** Minimal interface for a Node.js http.ClientRequest */ +export interface HttpClientRequest { + method?: string; + path?: string; + host?: string; + protocol?: string; + end(): void; + getHeader(name: string): string | string[] | number | undefined; + setHeader(name: string, value: string | string[] | number): void; + removeHeader(name: string): void; + prependListener(event: 'response', listener: (res: HttpIncomingMessage) => void): this; + prependListener(event: string | symbol, listener: (...args: unknown[]) => void): this; + on(event: string | symbol, listener: (...args: unknown[]) => void): this; + once(event: string | symbol, listener: (...args: unknown[]) => void): this; + listenerCount(event: string | symbol): number; + removeListener(event: string | symbol, listener: (...args: unknown[]) => void): this; +} + +/** Minimal interface for a Node.js http.ServerResponse */ +export interface HttpServerResponse { + statusCode: number; + statusMessage?: string; + headers: Record; + once(ev: string, ...data: unknown[]): this; + once(ev: 'close'): this; + on(ev: string | symbol, handler: (...data: unknown[]) => void): this; +} + +export interface HttpServer { + emit(ev: string, ...data: unknown[]): this; + emit(ev: 'request', request: HttpIncomingMessage, response: HttpServerResponse): this; +} + +export interface HttpSocket { + remoteAddress?: string; + remotePort?: number; + localAddress?: string; + localPort?: number; +} + +/** Minimal interface for a Node.js http.IncomingMessage */ +export interface HttpIncomingMessage { + statusCode?: number; + statusMessage?: string; + httpVersion?: string; + url?: string; + method?: string; + headers: Record; + socket?: HttpSocket; + aborted?: boolean; + complete?: boolean; + resume(): void; + on(event: 'end', listener: () => void): this; + on(event: string | symbol, listener: (...args: unknown[]) => void): this; + addListener(event: 'end', listener: () => void): this; + addListener(event: string | symbol, listener: (...args: unknown[]) => void): this; + off(event: string | symbol, listener: (...args: unknown[]) => void): this; + removeListener(event: string | symbol, listener: (...args: unknown[]) => void): this; +} + +/** Minimal interface for a Node.js http / https module export */ +export interface HttpExport { + request: (...args: unknown[]) => HttpClientRequest; + get: (...args: unknown[]) => HttpClientRequest; + [key: string]: unknown; +} + +export type HttpModuleExport = HttpExport | (HttpExport & { default: HttpExport }); + +export interface HttpInstrumentationOptions { + /** + * Whether to create spans for outgoing HTTP requests. + * @default true + */ + spans?: boolean; + + /** + * Whether to inject distributed trace propagation headers + * (`sentry-trace`, `baggage`, `traceparent`) into outgoing requests. + * @default false + */ + propagateTrace?: boolean; + + /** + * Skip span / breadcrumb creation for requests to matching URLs. + * Receives the full URL string and the outgoing request object. + */ + ignoreOutgoingRequests?: (url: string, request: HttpClientRequest) => boolean; + + /** + * Whether breadcrumbs should be recorded for outgoing requests. + * @default true + */ + breadcrumbs?: boolean; + + /** + * Called after the outgoing-request span is created by the client. + * Use this to add custom attributes to the span. + */ + outgoingRequestHook?: (span: Span, request: HttpClientRequest) => void; + + /** + * Called when the response is received by the client. + */ + outgoingResponseHook?: (span: Span, response: HttpIncomingMessage) => void; + + /** + * Called when both the request and response are available (after the + * response ends). Useful for adding attributes based on both objects. + */ + applyCustomAttributesOnSpan?: (span: Span, request: HttpClientRequest, response: HttpIncomingMessage) => void; + + /** + * Symbol to use for observing errors on EventEmitters without consuming + * them. Pass `EventEmitter.errorMonitor` from Node.js `events` module. + * Falls back to the plain `'error'` event string when not provided. + * + * Using the real `errorMonitor` symbol ensures that Sentry does not + * swallow errors before they reach user-supplied `'error'` handlers. + */ + errorMonitor?: symbol | string; + + /** + * Controls the maximum size of incoming HTTP request bodies attached to events. + * + * Available options: + * - 'none': No request bodies will be attached + * - 'small': Request bodies up to 1,000 bytes will be attached + * - 'medium': Request bodies up to 10,000 bytes will be attached (default) + * - 'always': Request bodies will always be attached + * + * Note that even with 'always' setting, bodies exceeding 1MB will never be attached + * for performance and security reasons. + * + * @default 'medium' + */ + maxRequestBodySize?: 'none' | 'small' | 'medium' | 'always'; + + /** + * Do not capture the request body for incoming HTTP requests to URLs where the given callback returns `true`. + * This can be useful for long running requests where the body is not needed and we want to avoid capturing it. + * + * @param url Contains the entire URL, including query string (if any), protocol, host, etc. of the incoming request. + * @param request Contains the {@type RequestOptions} object used to make the incoming request. + */ + ignoreRequestBody?: (url: string, request: HttpIncomingMessage) => boolean; + + /** + * Whether the integration should create [Sessions](https://docs.sentry.io/product/releases/health/#sessions) for incoming requests to track the health and crash-free rate of your releases in Sentry. + * Read more about Release Health: https://docs.sentry.io/product/releases/health/ + * + * Defaults to `true`. + */ + sessions?: boolean; + + /** + * Number of milliseconds until sessions tracked with `trackIncomingRequestsAsSessions` will be flushed as a session aggregate. + * + * Defaults to `60000` (60s). + */ + sessionFlushingDelayMS?: number; + + /** + * Optional callback that can be used by integrations to emit the 'request' + * event within a given Sentry or OTEL context, possibly after creating a + * span, as in the HttpServerSpansIntegration. + */ + wrapServerEmitRequest?: ( + request: HttpIncomingMessage, + response: HttpServerResponse, + normalizedRequest: RequestEventData, + next: () => void, + ) => void; + + /** + * Do not capture spans for incoming HTTP requests to URLs where the given callback returns `true`. + * Spans will be non recording if tracing is disabled. + * + * The `urlPath` param consists of the URL path and query string (if any) of the incoming request. + * For example: `'/users/details?id=123'` + * + * The `request` param contains the original {@type IncomingMessage} object of the incoming request. + * You can use it to filter on additional properties like method, headers, etc. + */ + ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean; + + /** + * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc. + * This helps reduce noise in your transactions. + * + * @default `true` + */ + ignoreStaticAssets?: boolean; + + /** + * Do not capture spans for incoming HTTP requests with the given status codes. + * By default, spans with some 3xx and 4xx status codes are ignored (see @default). + * Expects an array of status codes or a range of status codes, e.g. [[300,399], 404] would ignore 3xx and 404 status codes. + * + * @default `[[401, 404], [301, 303], [305, 399]]` + */ + ignoreStatusCodes?: (number | [number, number])[]; + + /** + * A hook that can be used to mutate the span for incoming requests. + * This is triggered after the span is created, but before it is recorded. + */ + onSpanCreated?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void; + + /** + * A hook that can be used to mutate the span one last time when the + * response is finished, eg to update the transaction name based on + * the RPC metadata. + */ + onSpanEnd?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void; +} diff --git a/packages/core/src/server-exports.ts b/packages/core/src/server-exports.ts new file mode 100644 index 000000000000..2d7bb385fb6f --- /dev/null +++ b/packages/core/src/server-exports.ts @@ -0,0 +1,45 @@ +// Server-only: server runtime client +export type { ServerRuntimeClientOptions } from './server-runtime-client'; +export { ServerRuntimeClient } from './server-runtime-client'; +export type { ServerRuntimeOptions } from './types-hoist/options'; + +// Server-only: Node.js module loading utilities +export { isNodeEnv, loadModule } from './utils/node'; + +// Server-only: Node.js stack trace parsing +export { filenameIsInApp, node, nodeStackLineParser } from './utils/node-stack-trace'; + +// Server-only: serverless/edge runtime utilities +export { vercelWaitUntil } from './utils/vercelWaitUntil'; +export { flushIfServerless } from './utils/flushIfServerless'; + +// Server-only: Node.js ANR (Application Not Responding) detection +export { callFrameToStackFrame, watchdogTimer } from './utils/anr'; + +// Server-only: Node.js timer utility (timer.unref() is not available in browsers) +export { safeUnref as _INTERNAL_safeUnref } from './utils/timer'; + +// Server-only: Express integration +export { patchExpressModule, setupExpressErrorHandler, expressErrorHandler } from './integrations/express/index'; +export type { + ExpressIntegrationOptions, + ExpressHandlerOptions, + ExpressMiddleware, + ExpressErrorMiddleware, +} from './integrations/express/types'; + +// Server-only: PostgreSQL integration +export { instrumentPostgresJsSql } from './integrations/postgresjs'; + +// Server-only: Node.js http/https module instrumentation +export { patchHttpModuleClient, patchHttpsModuleClient } from './integrations/http/client-patch'; +export { getHttpClientSubscriptions } from './integrations/http/client-subscriptions'; +export { addOutgoingRequestBreadcrumb } from './integrations/http/add-outgoing-request-breadcrumb'; +export { HTTP_ON_CLIENT_REQUEST, HTTP_ON_SERVER_REQUEST } from './integrations/http/constants'; +export type { + HttpInstrumentationOptions, + HttpClientRequest, + HttpIncomingMessage, + HttpServerResponse, + HttpModuleExport, +} from './integrations/http/types'; diff --git a/packages/core/src/server.ts b/packages/core/src/server.ts new file mode 100644 index 000000000000..10c4a02625bf --- /dev/null +++ b/packages/core/src/server.ts @@ -0,0 +1,11 @@ +/** + * The Sentry core SDK and integrations used by node, node-core, cloudflare, + * bun, deno, aws lambda, and other server-side platforms, where bundle size + * is less of an issue. + * + * This export should not contain anything strictly browser-specific. + */ +/* eslint-disable max-lines */ + +export * from './shared-exports'; +export * from './server-exports'; diff --git a/packages/core/src/shared-exports.ts b/packages/core/src/shared-exports.ts new file mode 100644 index 000000000000..3e7c19238339 --- /dev/null +++ b/packages/core/src/shared-exports.ts @@ -0,0 +1,543 @@ +/* eslint-disable max-lines */ + +export type { ClientClass as SentryCoreCurrentScopes } from './sdk'; +export type { AsyncContextStrategy } from './asyncContext/types'; +export type { Carrier } from './carrier'; +export type { OfflineStore, OfflineTransportOptions } from './transports/offline'; +export type { IntegrationIndex } from './integration'; + +export * from './tracing'; +export * from './semanticAttributes'; +export { createEventEnvelope, createSessionEnvelope, createSpanEnvelope } from './envelope'; +export { + captureCheckIn, + withMonitor, + captureException, + captureEvent, + captureMessage, + lastEventId, + close, + flush, + setContext, + setExtra, + setExtras, + setTag, + setTags, + setUser, + setConversationId, + isInitialized, + isEnabled, + startSession, + endSession, + captureSession, + addEventProcessor, +} from './exports'; +export { + getCurrentScope, + getIsolationScope, + getGlobalScope, + withScope, + withIsolationScope, + getClient, + getTraceContextFromScope, + registerExternalPropagationContext, + getExternalPropagationContext, + hasExternalPropagationContext, +} from './currentScopes'; +export { getDefaultCurrentScope, getDefaultIsolationScope } from './defaultScopes'; +export { setAsyncContextStrategy } from './asyncContext'; +export { getGlobalSingleton, getMainCarrier } from './carrier'; +export { makeSession, closeSession, updateSession } from './session'; +export { Scope } from './scope'; +export type { CaptureContext, ScopeContext, ScopeData } from './scope'; +export { notifyEventProcessors } from './eventProcessors'; +export { getEnvelopeEndpointWithUrlEncodedAuth, getReportDialogEndpoint, SENTRY_API_VERSION } from './api'; +export { Client } from './client'; +export { initAndBind, setCurrentClient } from './sdk'; +export { createTransport } from './transports/base'; +export { makeOfflineTransport } from './transports/offline'; +export { makeMultiplexedTransport, MULTIPLEXED_TRANSPORT_EXTRA_KEY } from './transports/multiplexed'; +export { getIntegrationsToSetup, addIntegration, defineIntegration, installedIntegrations } from './integration'; +export { + _INTERNAL_skipAiProviderWrapping, + _INTERNAL_shouldSkipAiProviderWrapping, + _INTERNAL_clearAiProviderSkips, +} from './utils/ai/providerSkip'; +export { envToBool } from './utils/envToBool'; +export { applyScopeDataToEvent, mergeScopeData, getCombinedScopeData } from './utils/scopeData'; +export { prepareEvent } from './utils/prepareEvent'; +export type { ExclusiveEventHintOrCaptureContext } from './utils/prepareEvent'; +export { createCheckInEnvelope } from './checkin'; +export { hasSpansEnabled } from './utils/hasSpansEnabled'; +export { withStreamedSpan } from './tracing/spans/beforeSendSpan'; +export { isStreamedBeforeSendSpanCallback } from './tracing/spans/beforeSendSpan'; +export { isSentryRequestUrl } from './utils/isSentryRequestUrl'; +export { handleCallbackErrors } from './utils/handleCallbackErrors'; +export { parameterize, fmt } from './utils/parameterize'; +export type { HandleTunnelRequestOptions } from './utils/tunnel'; +export { handleTunnelRequest } from './utils/tunnel'; + +export { addAutoIpAddressToSession } from './utils/ipAddress'; +// eslint-disable-next-line deprecation/deprecation +export { addAutoIpAddressToUser } from './utils/ipAddress'; +export { + convertSpanLinksForEnvelope, + spanToTraceHeader, + spanToJSON, + spanToStreamedSpanJSON, + spanIsSampled, + spanToTraceContext, + getSpanDescendants, + getStatusMessage, + getRootSpan, + INTERNAL_getSegmentSpan, + getActiveSpan, + addChildSpanToSpan, + spanTimeInputToSeconds, + updateSpanName, +} from './utils/spanUtils'; +export { _setSpanForScope as _INTERNAL_setSpanForScope } from './utils/spanOnScope'; +export { parseSampleRate } from './utils/parseSampleRate'; +export { applySdkMetadata } from './utils/sdkMetadata'; +export { getTraceData } from './utils/traceData'; +export { shouldPropagateTraceForUrl } from './utils/tracePropagationTargets'; +export { getTraceMetaTags } from './utils/meta'; +export { debounce } from './utils/debounce'; +export { makeWeakRef, derefWeakRef } from './utils/weakRef'; +export type { MaybeWeakRef } from './utils/weakRef'; +export { shouldIgnoreSpan } from './utils/should-ignore-span'; +export { + winterCGHeadersToDict, + winterCGRequestToRequestData, + httpRequestToRequestData, + extractQueryParamsFromUrl, + headersToDict, + httpHeadersToSpanAttributes, +} from './utils/request'; +export { DEFAULT_ENVIRONMENT, DEV_ENVIRONMENT } from './constants'; +export { addBreadcrumb } from './breadcrumbs'; +export { functionToStringIntegration } from './integrations/functiontostring'; +// eslint-disable-next-line deprecation/deprecation +export { inboundFiltersIntegration } from './integrations/eventFilters'; +export { eventFiltersIntegration } from './integrations/eventFilters'; +export { linkedErrorsIntegration } from './integrations/linkederrors'; +export { moduleMetadataIntegration } from './integrations/moduleMetadata'; +export { requestDataIntegration } from './integrations/requestdata'; +export { captureConsoleIntegration } from './integrations/captureconsole'; +export { dedupeIntegration } from './integrations/dedupe'; +export { extraErrorDataIntegration } from './integrations/extraerrordata'; +export { rewriteFramesIntegration } from './integrations/rewriteframes'; +export { supabaseIntegration, instrumentSupabaseClient } from './integrations/supabase'; +export { zodErrorsIntegration } from './integrations/zoderrors'; +export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter'; +export { consoleIntegration } from './integrations/console'; +export type { FeatureFlagsIntegration } from './integrations/featureFlags'; +export { featureFlagsIntegration } from './integrations/featureFlags'; +export { growthbookIntegration } from './integrations/featureFlags'; +export { conversationIdIntegration } from './integrations/conversationId'; + +export { profiler } from './profiling'; +// eslint thinks the entire function is deprecated (while only one overload is actually deprecated) +// Therefore: +// eslint-disable-next-line deprecation/deprecation +export { instrumentFetchRequest, _INTERNAL_getTracingHeadersForFetchRequest } from './fetch'; +export { trpcMiddleware } from './trpc'; +export { wrapMcpServerWithSentry } from './integrations/mcp-server'; +export { captureFeedback } from './feedback'; +export type { ReportDialogOptions } from './report-dialog'; +export { _INTERNAL_captureLog, _INTERNAL_flushLogsBuffer, _INTERNAL_captureSerializedLog } from './logs/internal'; +export * as logger from './logs/public-api'; +export { consoleLoggingIntegration } from './logs/console-integration'; +export { + _INTERNAL_captureMetric, + _INTERNAL_flushMetricsBuffer, + _INTERNAL_captureSerializedMetric, +} from './metrics/internal'; +export * as metrics from './metrics/public-api'; +export type { MetricOptions } from './metrics/public-api'; +export { createConsolaReporter } from './integrations/consola'; +export { addVercelAiProcessors } from './tracing/vercel-ai'; +export { _INTERNAL_getSpanContextForToolCallId, _INTERNAL_cleanupToolCallSpanContext } from './tracing/vercel-ai/utils'; +export { toolCallSpanContextMap as _INTERNAL_toolCallSpanContextMap } from './tracing/vercel-ai/constants'; +export { instrumentOpenAiClient } from './tracing/openai'; +export { OPENAI_INTEGRATION_NAME } from './tracing/openai/constants'; +export { instrumentAnthropicAiClient } from './tracing/anthropic-ai'; +export { ANTHROPIC_AI_INTEGRATION_NAME } from './tracing/anthropic-ai/constants'; +export { instrumentGoogleGenAIClient } from './tracing/google-genai'; +export { GOOGLE_GENAI_INTEGRATION_NAME } from './tracing/google-genai/constants'; +export type { GoogleGenAIResponse } from './tracing/google-genai/types'; +export { createLangChainCallbackHandler, instrumentLangChainEmbeddings } from './tracing/langchain'; +export { LANGCHAIN_INTEGRATION_NAME } from './tracing/langchain/constants'; +export type { LangChainOptions, LangChainIntegration } from './tracing/langchain/types'; +export { instrumentStateGraphCompile, instrumentLangGraph } from './tracing/langgraph'; +export { LANGGRAPH_INTEGRATION_NAME } from './tracing/langgraph/constants'; +export type { LangGraphOptions, LangGraphIntegration, CompiledGraph } from './tracing/langgraph/types'; +export type { OpenAiClient, OpenAiOptions, InstrumentedMethod } from './tracing/openai/types'; +export type { + AnthropicAiClient, + AnthropicAiOptions, + AnthropicAiInstrumentedMethod, + AnthropicAiResponse, +} from './tracing/anthropic-ai/types'; +export type { + GoogleGenAIClient, + GoogleGenAIChat, + GoogleGenAIOptions, + GoogleGenAIInstrumentedMethod, +} from './tracing/google-genai/types'; +// eslint-disable-next-line deprecation/deprecation +export type { GoogleGenAIIstrumentedMethod } from './tracing/google-genai/types'; + +export { SpanBuffer } from './tracing/spans/spanBuffer'; +export { hasSpanStreamingEnabled } from './tracing/spans/hasSpanStreamingEnabled'; +export { spanStreamingIntegration } from './integrations/spanStreaming'; + +export type { FeatureFlag } from './utils/featureFlags'; + +export { + _INTERNAL_copyFlagsFromScopeToEvent, + _INTERNAL_insertFlagToScope, + _INTERNAL_addFeatureFlagToActiveSpan, + _INTERNAL_FLAG_BUFFER_SIZE, + _INTERNAL_MAX_FLAGS_PER_SPAN, +} from './utils/featureFlags'; + +export { applyAggregateErrorsToEvent } from './utils/aggregate-errors'; +export { getBreadcrumbLogLevelFromHttpStatusCode } from './utils/breadcrumb-log-level'; +export { dsnFromString, dsnToString, makeDsn } from './utils/dsn'; +// eslint-disable-next-line deprecation/deprecation +export { SentryError } from './utils/error'; +export { GLOBAL_OBJ } from './utils/worldwide'; +export type { InternalGlobal } from './utils/worldwide'; +export { addConsoleInstrumentationHandler } from './instrument/console'; +export { addFetchEndInstrumentationHandler, addFetchInstrumentationHandler } from './instrument/fetch'; +export { addGlobalErrorInstrumentationHandler } from './instrument/globalError'; +export { addGlobalUnhandledRejectionInstrumentationHandler } from './instrument/globalUnhandledRejection'; +export { addHandler, maybeInstrument, resetInstrumentationHandlers, triggerHandlers } from './instrument/handlers'; +export { + isDOMError, + isDOMException, + isElement, + isError, + isErrorEvent, + isEvent, + isInstanceOf, + isParameterizedString, + isPlainObject, + isPrimitive, + isRegExp, + isString, + isSyntheticEvent, + isThenable, + isVueViewModel, +} from './utils/is'; +export { isBrowser } from './utils/isBrowser'; +export { CONSOLE_LEVELS, consoleSandbox, debug, originalConsoleMethods } from './utils/debug-logger'; +export type { SentryDebugLogger } from './utils/debug-logger'; +export { + addContextToFrame, + addExceptionMechanism, + addExceptionTypeValue, + checkOrSetAlreadyCaught, + isAlreadyCaptured, + getEventDescription, + parseSemver, + uuid4, +} from './utils/misc'; +export { normalize, normalizeToSize, normalizeUrlToBase } from './utils/normalize'; +export { + addNonEnumerableProperty, + convertToPlainObject, + // eslint-disable-next-line deprecation/deprecation + dropUndefinedKeys, + extractExceptionKeysForMessage, + fill, + getOriginalFunction, + markFunctionWrapped, + objectify, +} from './utils/object'; +export { basename, dirname, isAbsolute, join, normalizePath, relative, resolve } from './utils/path'; +export { makePromiseBuffer, SENTRY_BUFFER_FULL_ERROR } from './utils/promisebuffer'; +export type { PromiseBuffer } from './utils/promisebuffer'; +export { severityLevelFromString } from './utils/severity'; +export { replaceExports } from './utils/exports'; +export { + UNKNOWN_FUNCTION, + createStackParser, + getFramesFromEvent, + getFunctionName, + stackParserFromStackParserOptions, + stripSentryFramesAndReverse, +} from './utils/stacktrace'; +export { isMatchingPattern, safeJoin, snipLine, stringMatchesSomePattern, truncate } from './utils/string'; +export { + isNativeFunction, + supportsDOMException, + supportsErrorEvent, + // eslint-disable-next-line deprecation/deprecation + supportsFetch, + // eslint-disable-next-line deprecation/deprecation + supportsReferrerPolicy, +} from './utils/supports'; +export { SyncPromise, rejectedSyncPromise, resolvedSyncPromise } from './utils/syncpromise'; +export { browserPerformanceTimeOrigin, dateTimestampInSeconds, timestampInSeconds } from './utils/time'; +export { + TRACEPARENT_REGEXP, + extractTraceparentData, + generateSentryTraceHeader, + propagationContextFromHeaders, + shouldContinueTrace, + generateTraceparentHeader, +} from './utils/tracing'; +export { getSDKSource, isBrowserBundle } from './utils/env'; +export type { SdkSource } from './utils/env'; +export { + addItemToEnvelope, + createAttachmentEnvelopeItem, + createEnvelope, + createEventEnvelopeHeaders, + createSpanEnvelopeItem, + envelopeContainsItemType, + envelopeItemTypeToDataCategory, + forEachEnvelopeItem, + getSdkMetadataForEnvelopeHeader, + parseEnvelope, + serializeEnvelope, +} from './utils/envelope'; +export { createClientReportEnvelope } from './utils/clientreport'; +export { + DEFAULT_RETRY_AFTER, + disabledUntil, + isRateLimited, + parseRetryAfterHeader, + updateRateLimits, +} from './utils/ratelimit'; +export type { RateLimits } from './utils/ratelimit'; +export { + MAX_BAGGAGE_STRING_LENGTH, + SENTRY_BAGGAGE_KEY_PREFIX, + SENTRY_BAGGAGE_KEY_PREFIX_REGEX, + baggageHeaderToDynamicSamplingContext, + dynamicSamplingContextToSentryBaggageHeader, + parseBaggageHeader, + objectToBaggageHeader, +} from './utils/baggage'; +export { + getSanitizedUrlString, + parseUrl, + stripUrlQueryAndFragment, + parseStringToURLObject, + getHttpSpanDetailsFromUrlObject, + isURLObjectRelative, + getSanitizedUrlStringFromUrlObject, + stripDataUrlContent, +} from './utils/url'; +export { + eventFromMessage, + eventFromUnknownInput, + exceptionFromError, + parseStackFrames, + _enhanceErrorWithSentryInfo as _INTERNAL_enhanceErrorWithSentryInfo, +} from './utils/eventbuilder'; +export { LRUMap } from './utils/lru'; +export { generateTraceId, generateSpanId } from './utils/propagationContext'; +export { SDK_VERSION } from './utils/version'; +export { getDebugImagesForResources, getFilenameToDebugIdMap } from './utils/debug-ids'; +export { getFilenameToMetadataMap } from './metadata'; +export { escapeStringForRegex } from './vendor/escapeStringForRegex'; + +export type { Attachment } from './types-hoist/attachment'; +export type { Breadcrumb, BreadcrumbHint, FetchBreadcrumbData, FetchBreadcrumbHint } from './types-hoist/breadcrumb'; +export type { ClientReport, Outcome, EventDropReason } from './types-hoist/clientreport'; +export type { + Context, + Contexts, + DeviceContext, + OsContext, + AppContext, + CultureContext, + TraceContext, + CloudResourceContext, + MissingInstrumentationContext, +} from './types-hoist/context'; +export type { DataCategory } from './types-hoist/datacategory'; +export type { DsnComponents, DsnLike, DsnProtocol } from './types-hoist/dsn'; +export type { DebugImage, DebugMeta } from './types-hoist/debugMeta'; +export type { + AttachmentItem, + BaseEnvelopeHeaders, + BaseEnvelopeItemHeaders, + ClientReportEnvelope, + ClientReportItem, + DynamicSamplingContext, + Envelope, + EnvelopeItemType, + EnvelopeItem, + EventEnvelope, + EventEnvelopeHeaders, + EventItem, + ReplayEnvelope, + FeedbackItem, + SessionEnvelope, + SessionItem, + UserFeedbackItem, + CheckInItem, + CheckInEnvelope, + RawSecurityEnvelope, + RawSecurityItem, + ProfileItem, + ProfileChunkEnvelope, + ProfileChunkItem, + SpanEnvelope, + StreamedSpanEnvelope, + SpanItem, + LogEnvelope, + MetricEnvelope, +} from './types-hoist/envelope'; +export type { ExtendedError } from './types-hoist/error'; +export type { Event, EventHint, EventType, ErrorEvent, TransactionEvent } from './types-hoist/event'; +export type { EventProcessor } from './types-hoist/eventprocessor'; +export type { Exception } from './types-hoist/exception'; +export type { Extra, Extras } from './types-hoist/extra'; +export type { Integration, IntegrationFn } from './types-hoist/integration'; +export type { Mechanism } from './types-hoist/mechanism'; +export type { ExtractedNodeRequestData, HttpHeaderValue, Primitive, WorkerLocation } from './types-hoist/misc'; +export type { ClientOptions, CoreOptions as Options } from './types-hoist/options'; +export type { Package } from './types-hoist/package'; +export type { PolymorphicEvent, PolymorphicRequest } from './types-hoist/polymorphics'; +export type { + ThreadId, + FrameId, + StackId, + ThreadCpuSample, + ThreadCpuStack, + ThreadCpuFrame, + ThreadCpuProfile, + ContinuousThreadCpuProfile, + Profile, + ProfileChunk, +} from './types-hoist/profiling'; +export type { + ReplayEndEvent, + ReplayEvent, + ReplayRecordingData, + ReplayRecordingMode, + ReplayStartEvent, + ReplayStopReason, +} from './types-hoist/replay'; +export type { + FeedbackEvent, + FeedbackFormData, + FeedbackInternalOptions, + FeedbackModalIntegration, + FeedbackScreenshotIntegration, + SendFeedback, + SendFeedbackParams, + UserFeedback, +} from './types-hoist/feedback'; +export type { + QueryParams, + RequestEventData, + RequestHookInfo, + ResponseHookInfo, + SanitizedRequestData, +} from './types-hoist/request'; +export type { Runtime } from './types-hoist/runtime'; +export type { SdkInfo } from './types-hoist/sdkinfo'; +export type { SdkMetadata } from './types-hoist/sdkmetadata'; +export type { + SessionAggregates, + AggregationCounts, + Session, + SessionContext, + SessionStatus, + SerializedSession, +} from './types-hoist/session'; +export type { SeverityLevel } from './types-hoist/severity'; +export type { + Span, + SentrySpanArguments, + SpanOrigin, + SpanAttributeValue, + SpanAttributes, + SpanTimeInput, + SpanJSON, + SpanContextData, + TraceFlag, + SerializedStreamedSpan, + SerializedStreamedSpanContainer, + StreamedSpanJSON, +} from './types-hoist/span'; +export type { SpanStatus } from './types-hoist/spanStatus'; +export type { Log, LogSeverityLevel } from './types-hoist/log'; +export type { SpanLink } from './types-hoist/link'; +export type { + Metric, + MetricType, + SerializedMetric, + SerializedMetricContainer, + // eslint-disable-next-line deprecation/deprecation + SerializedMetricAttributeValue, +} from './types-hoist/metric'; +export type { TimedEvent } from './types-hoist/timedEvent'; +export type { StackFrame } from './types-hoist/stackframe'; +export type { Stacktrace, StackParser, StackLineParser, StackLineParserFn } from './types-hoist/stacktrace'; +export type { PropagationContext, TracePropagationTargets, SerializedTraceData } from './types-hoist/tracing'; +export type { StartSpanOptions } from './types-hoist/startSpanOptions'; +export type { TraceparentData, TransactionSource } from './types-hoist/transaction'; +export type { + TracesSamplerSamplingContext, + CustomSamplingContext, + SamplingContext, +} from './types-hoist/samplingcontext'; +export type { + DurationUnit, + InformationUnit, + FractionUnit, + MeasurementUnit, + NoneUnit, + Measurements, +} from './types-hoist/measurement'; +export type { Thread } from './types-hoist/thread'; +export type { + Transport, + TransportRequest, + TransportMakeRequestResponse, + InternalBaseTransportOptions, + BaseTransportOptions, + TransportRequestExecutor, +} from './types-hoist/transport'; +export type { User } from './types-hoist/user'; +export type { WebFetchHeaders, WebFetchRequest } from './types-hoist/webfetchapi'; +export type { WrappedFunction } from './types-hoist/wrappedfunction'; +export type { + HandlerDataFetch, + HandlerDataConsole, + HandlerDataError, + HandlerDataUnhandledRejection, + ConsoleLevel, +} from './types-hoist/instrument'; +export type { + CheckIn, + MonitorConfig, + FinishedCheckIn, + InProgressCheckIn, + SerializedCheckIn, +} from './types-hoist/checkin'; +export type { ParameterizedString } from './types-hoist/parameterize'; +export type { ContinuousProfiler, ProfilingIntegration, Profiler } from './types-hoist/profiling'; +export type { ViewHierarchyData, ViewHierarchyWindow } from './types-hoist/view-hierarchy'; +export type { LegacyCSPReport } from './types-hoist/csp'; +export type { SerializedLog, SerializedLogContainer } from './types-hoist/log'; +export type { + BuildTimeOptionsBase, + UnstableVitePluginOptions, + UnstableRollupPluginOptions, + UnstableWebpackPluginOptions, +} from './build-time-plugins/buildTimeOptionsBase'; +export type { RandomSafeContextRunner as _INTERNAL_RandomSafeContextRunner } from './utils/randomSafeContext'; +export { + withRandomSafeContext as _INTERNAL_withRandomSafeContext, + safeMathRandom as _INTERNAL_safeMathRandom, + safeDateNow as _INTERNAL_safeDateNow, +} from './utils/randomSafeContext'; diff --git a/packages/core/src/tracing/index.ts b/packages/core/src/tracing/index.ts index 3d3736876015..9b56045b37f3 100644 --- a/packages/core/src/tracing/index.ts +++ b/packages/core/src/tracing/index.ts @@ -13,6 +13,7 @@ export { withActiveSpan, suppressTracing, startNewTrace, + SUPPRESS_TRACING_KEY, } from './trace'; export { getDynamicSamplingContextFromClient, diff --git a/packages/core/src/tracing/trace.ts b/packages/core/src/tracing/trace.ts index 08411722cedf..ebf35e360af4 100644 --- a/packages/core/src/tracing/trace.ts +++ b/packages/core/src/tracing/trace.ts @@ -36,7 +36,7 @@ import { SPAN_STATUS_ERROR } from './spanstatus'; import { setCapturedScopesOnSpan } from './utils'; import type { Client } from '../client'; -const SUPPRESS_TRACING_KEY = '__SENTRY_SUPPRESS_TRACING__'; +export const SUPPRESS_TRACING_KEY = '__SENTRY_SUPPRESS_TRACING__'; /** * Wraps a function with a transaction/span and finishes the span after the function is done. diff --git a/packages/core/src/utils/get-default-export.ts b/packages/core/src/utils/get-default-export.ts new file mode 100644 index 000000000000..ef37fea574f3 --- /dev/null +++ b/packages/core/src/utils/get-default-export.ts @@ -0,0 +1,24 @@ +/** + * Often we patch a module's default export, but we want to be able to do + * something like this: + * + * ```ts + * patchTheThing(await import('the-thing')); + * ``` + * + * Or like this: + * + * ```ts + * import theThing from 'the-thing'; + * patchTheThing(theThing); + * ``` + */ +export function getDefaultExport(moduleExport: T | { default: T }): T { + return ( + (!!moduleExport && + typeof moduleExport === 'object' && + 'default' in moduleExport && + (moduleExport as { default: T }).default) || + (moduleExport as T) + ); +} diff --git a/packages/core/src/utils/url.ts b/packages/core/src/utils/url.ts index bf0c17dbc278..9365dc8ae496 100644 --- a/packages/core/src/utils/url.ts +++ b/packages/core/src/utils/url.ts @@ -188,7 +188,7 @@ export function getHttpSpanDetailsFromUrlObject( } if (!isURLObjectRelative(urlObject)) { - attributes[SEMANTIC_ATTRIBUTE_URL_FULL] = urlObject.href; + attributes[SEMANTIC_ATTRIBUTE_URL_FULL] = stripDataUrlContent(urlObject.href); if (urlObject.port) { attributes['url.port'] = urlObject.port; } diff --git a/packages/core/test/lib/integrations/express/utils.test.ts b/packages/core/test/lib/integrations/express/utils.test.ts index b41d89076900..a7ec32d96e8d 100644 --- a/packages/core/test/lib/integrations/express/utils.test.ts +++ b/packages/core/test/lib/integrations/express/utils.test.ts @@ -15,7 +15,6 @@ import { getLayerMetadata, getLayerPath, getRouterPath, - hasDefaultProp, isExpressWithoutRouterPrototype, isExpressWithRouterPrototype, isLayerIgnored, @@ -368,14 +367,6 @@ describe('getConstructedRoute', () => { }); }); -describe('hasDefaultProp', () => { - it('returns detects the presence of a default function prop', () => { - expect(hasDefaultProp({ default: function express() {} })).toBe(true); - expect(hasDefaultProp({ default: 'other thing' })).toBe(false); - expect(hasDefaultProp({})).toBe(false); - }); -}); - describe('isExpressWith(out)RouterPrototype', () => { it('detects what kind of express this is', () => { expect(isExpressWithoutRouterPrototype({})).toBe(false); diff --git a/packages/core/test/lib/utils/get-default-export.test.ts b/packages/core/test/lib/utils/get-default-export.test.ts new file mode 100644 index 000000000000..2a12e8d1d1a9 --- /dev/null +++ b/packages/core/test/lib/utils/get-default-export.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; +import { getDefaultExport } from '../../../src/utils/get-default-export'; + +describe('getDefaultExport', () => { + it('returns the default export if there is one', () => { + const mod = { + default: () => {}, + }; + expect(getDefaultExport(mod)).toBe(mod.default); + }); + it('returns the module export if no default', () => { + const mod = {}; + expect(getDefaultExport(mod)).toBe(mod); + }); + it('returns the module if a function and not plain object', () => { + const mod = Object.assign(function () {}, { + default: () => {}, + }); + expect(getDefaultExport(mod)).toBe(mod); + }); + it('returns the module if a default is falsey', () => { + const mod = Object.assign(function () {}, { + default: false, + }); + expect(getDefaultExport(mod)).toBe(mod); + }); +}); diff --git a/packages/core/tsconfig.test.json b/packages/core/tsconfig.test.json index 5a80d11f7055..40725a892888 100644 --- a/packages/core/tsconfig.test.json +++ b/packages/core/tsconfig.test.json @@ -5,7 +5,6 @@ "compilerOptions": { "lib": ["DOM", "es2020"], - "module": "ESNext", // support dynamic import() // should include all types from `./tsconfig.json` plus types for all test frameworks used "types": ["node"] diff --git a/packages/core/tsconfig.types.json b/packages/core/tsconfig.types.json index 65455f66bd75..de9b6935694a 100644 --- a/packages/core/tsconfig.types.json +++ b/packages/core/tsconfig.types.json @@ -2,6 +2,8 @@ "extends": "./tsconfig.json", "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", "declaration": true, "declarationMap": true, "emitDeclarationOnly": true, diff --git a/packages/effect/rollup.npm.config.mjs b/packages/effect/rollup.npm.config.mjs index 211157646473..dde3327a2501 100644 --- a/packages/effect/rollup.npm.config.mjs +++ b/packages/effect/rollup.npm.config.mjs @@ -9,9 +9,11 @@ const baseConfig = makeBaseNPMConfig({ }, }); -const defaultExternal = baseConfig.external || []; +const defaultExternal = baseConfig.external; +const isDefaultExternal = + typeof defaultExternal === 'function' ? defaultExternal : id => (defaultExternal || []).includes(id); baseConfig.external = id => { - if (defaultExternal.includes(id)) { + if (isDefaultExternal(id)) { return true; } diff --git a/packages/ember/tsconfig.json b/packages/ember/tsconfig.json index e472924f4d0f..04eae83278b0 100644 --- a/packages/ember/tsconfig.json +++ b/packages/ember/tsconfig.json @@ -4,7 +4,7 @@ "target": "es2022", "lib": ["DOM", "ES2022"], "allowJs": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "allowSyntheticDefaultImports": true, "alwaysStrict": true, "strictNullChecks": true, diff --git a/packages/hono/rollup.npm.config.mjs b/packages/hono/rollup.npm.config.mjs index 2a03d7540bdc..83a43b881f1f 100644 --- a/packages/hono/rollup.npm.config.mjs +++ b/packages/hono/rollup.npm.config.mjs @@ -11,7 +11,7 @@ const baseConfig = makeBaseNPMConfig({ const defaultExternal = baseConfig.external; baseConfig.external = id => { - if (defaultExternal.includes(id)) { + if (defaultExternal(id)) { return true; } // Mark all hono subpaths as external diff --git a/packages/integration-shims/src/BrowserTracing.ts b/packages/integration-shims/src/BrowserTracing.ts index f92f3a63d6d8..aaafbd537ec8 100644 --- a/packages/integration-shims/src/BrowserTracing.ts +++ b/packages/integration-shims/src/BrowserTracing.ts @@ -1,4 +1,4 @@ -import { consoleSandbox, defineIntegration } from '@sentry/core'; +import { consoleSandbox, defineIntegration } from '@sentry/core/browser'; /** * This is a shim for the BrowserTracing integration. diff --git a/packages/integration-shims/src/ElementTiming.ts b/packages/integration-shims/src/ElementTiming.ts index 8a521163f7e1..1eb43d9cf682 100644 --- a/packages/integration-shims/src/ElementTiming.ts +++ b/packages/integration-shims/src/ElementTiming.ts @@ -1,4 +1,4 @@ -import { consoleSandbox, defineIntegration } from '@sentry/core'; +import { consoleSandbox, defineIntegration } from '@sentry/core/browser'; /** * This is a shim for the ElementTiming integration. diff --git a/packages/integration-shims/src/Feedback.ts b/packages/integration-shims/src/Feedback.ts index dd56bd273717..aa21f81494e7 100644 --- a/packages/integration-shims/src/Feedback.ts +++ b/packages/integration-shims/src/Feedback.ts @@ -1,5 +1,5 @@ -import type { Integration } from '@sentry/core'; -import { consoleSandbox } from '@sentry/core'; +import type { Integration } from '@sentry/core/browser'; +import { consoleSandbox } from '@sentry/core/browser'; import { FAKE_FUNCTION } from './common'; const FEEDBACK_INTEGRATION_METHODS = ['attachTo', 'createForm', 'createWidget', 'remove'] as const; diff --git a/packages/integration-shims/src/Replay.ts b/packages/integration-shims/src/Replay.ts index eee5cfbb2ef7..e532c49bf276 100644 --- a/packages/integration-shims/src/Replay.ts +++ b/packages/integration-shims/src/Replay.ts @@ -1,5 +1,5 @@ -import type { Integration } from '@sentry/core'; -import { consoleSandbox } from '@sentry/core'; +import type { Integration } from '@sentry/core/browser'; +import { consoleSandbox } from '@sentry/core/browser'; import { FAKE_FUNCTION } from './common'; const REPLAY_INTEGRATION_METHODS = ['start', 'stop', 'flush'] as const; diff --git a/packages/integration-shims/src/SpanStreaming.ts b/packages/integration-shims/src/SpanStreaming.ts index 7b445f086145..269770b9ab21 100644 --- a/packages/integration-shims/src/SpanStreaming.ts +++ b/packages/integration-shims/src/SpanStreaming.ts @@ -1,4 +1,4 @@ -import { consoleSandbox, defineIntegration } from '@sentry/core'; +import { consoleSandbox, defineIntegration } from '@sentry/core/browser'; /** * This is a shim for the SpanStreaming integration. diff --git a/packages/integration-shims/src/launchDarkly.ts b/packages/integration-shims/src/launchDarkly.ts index 76750f5c863c..08203b6a74ad 100644 --- a/packages/integration-shims/src/launchDarkly.ts +++ b/packages/integration-shims/src/launchDarkly.ts @@ -1,4 +1,4 @@ -import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core'; +import { consoleSandbox, defineIntegration, isBrowser } from '@sentry/core/browser'; import { FAKE_FUNCTION } from './common'; /** diff --git a/packages/integration-shims/src/logs.ts b/packages/integration-shims/src/logs.ts index 33af020efefc..7544a80cd30d 100644 --- a/packages/integration-shims/src/logs.ts +++ b/packages/integration-shims/src/logs.ts @@ -1,5 +1,5 @@ -import type { Integration, ParameterizedString } from '@sentry/core'; -import { consoleSandbox, defineIntegration } from '@sentry/core'; +import type { Integration, ParameterizedString } from '@sentry/core/browser'; +import { consoleSandbox, defineIntegration } from '@sentry/core/browser'; import { FAKE_FUNCTION } from './common'; import { DEBUG_BUILD } from './debug-build'; diff --git a/packages/integration-shims/tsconfig.json b/packages/integration-shims/tsconfig.json index bf45a09f2d71..0b788fab5eae 100644 --- a/packages/integration-shims/tsconfig.json +++ b/packages/integration-shims/tsconfig.json @@ -4,6 +4,8 @@ "include": ["src/**/*"], "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" // package-specific options } } diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index 1db0afa109c0..9695fc0ee64c 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -102,7 +102,7 @@ "scripts": { "build": "run-p build:transpile build:types", "build:dev": "yarn build", - "build:transpile": "ts-node scripts/buildRollup.ts", + "build:transpile": "ts-node --project tsconfig.tsnode.json scripts/buildRollup.ts", "build:types": "run-s build:types:core build:types:downlevel", "build:types:core": "tsc -p tsconfig.types.json", "build:types:downlevel": "yarn downlevel-dts build/types build/types-ts3.8 --to ts3.8", diff --git a/packages/nextjs/tsconfig.json b/packages/nextjs/tsconfig.json index bf45a09f2d71..202590772b10 100644 --- a/packages/nextjs/tsconfig.json +++ b/packages/nextjs/tsconfig.json @@ -5,5 +5,7 @@ "compilerOptions": { // package-specific options + "module": "esnext", + "moduleResolution": "bundler" } } diff --git a/packages/nextjs/tsconfig.tsnode.json b/packages/nextjs/tsconfig.tsnode.json new file mode 100644 index 000000000000..bf45a09f2d71 --- /dev/null +++ b/packages/nextjs/tsconfig.tsnode.json @@ -0,0 +1,9 @@ +{ + "extends": "../../tsconfig.json", + + "include": ["src/**/*"], + + "compilerOptions": { + // package-specific options + } +} diff --git a/packages/node-core/src/index.ts b/packages/node-core/src/index.ts index a9633b94c25d..8ce1cade960d 100644 --- a/packages/node-core/src/index.ts +++ b/packages/node-core/src/index.ts @@ -3,6 +3,9 @@ export { httpIntegration } from './integrations/http'; export { httpServerSpansIntegration } from './integrations/http/httpServerSpansIntegration'; export { httpServerIntegration } from './integrations/http/httpServerIntegration'; +export type { HttpServerIntegrationOptions } from './integrations/http/httpServerIntegration'; +export type { HttpServerSpansIntegrationOptions } from './integrations/http/httpServerSpansIntegration'; + export { SentryHttpInstrumentation, type SentryHttpInstrumentationOptions, diff --git a/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts b/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts index b25d32138aa9..3e59f6de6041 100644 --- a/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts +++ b/packages/node-core/src/integrations/http/SentryHttpInstrumentation.ts @@ -1,48 +1,28 @@ -/* eslint-disable max-lines */ -import type { ChannelListener } from 'node:diagnostics_channel'; -import { subscribe, unsubscribe } from 'node:diagnostics_channel'; -import { errorMonitor } from 'node:events'; +import { subscribe } from 'node:diagnostics_channel'; import type * as http from 'node:http'; -import type * as https from 'node:https'; -import { context, SpanStatusCode, trace } from '@opentelemetry/api'; +import { context, trace } from '@opentelemetry/api'; import { isTracingSuppressed } from '@opentelemetry/core'; import type { InstrumentationConfig } from '@opentelemetry/instrumentation'; import { InstrumentationBase, InstrumentationNodeModuleDefinition } from '@opentelemetry/instrumentation'; -import { - ATTR_HTTP_RESPONSE_STATUS_CODE, - ATTR_NETWORK_PEER_ADDRESS, - ATTR_NETWORK_PEER_PORT, - ATTR_NETWORK_PROTOCOL_VERSION, - ATTR_NETWORK_TRANSPORT, - ATTR_URL_FULL, - ATTR_USER_AGENT_ORIGINAL, - SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH, - SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED, -} from '@opentelemetry/semantic-conventions'; -import type { Span, SpanAttributes, SpanStatus } from '@sentry/core'; -import { - debug, - getHttpSpanDetailsFromUrlObject, - getSpanStatusFromHttpCode, - LRUMap, - parseStringToURLObject, - SDK_VERSION, - SEMANTIC_ATTRIBUTE_SENTRY_OP, - startInactiveSpan, +import type { ClientRequest, IncomingMessage, ServerResponse } from 'node:http'; +import type { + HttpClientRequest, + HttpIncomingMessage, + HttpInstrumentationOptions, + HttpModuleExport, + Span, } from '@sentry/core'; -import { DEBUG_BUILD } from '../../debug-build'; +import { getHttpClientSubscriptions, patchHttpModuleClient, patchHttpsModuleClient, SDK_VERSION } from '@sentry/core'; import { INSTRUMENTATION_NAME } from './constants'; -import { - addRequestBreadcrumb, - addTracePropagationHeadersToOutgoingRequest, - getClientRequestUrl, - getRequestOptions, -} from './outgoing-requests'; +import { HTTP_ON_CLIENT_REQUEST } from '@sentry/core'; +import { NODE_VERSION } from '../../nodeVersion'; +import { errorMonitor } from 'node:events'; +import { getRequestOptions } from '../../utils/outgoingHttpRequest'; -type Http = typeof http; -type Https = typeof https; -type IncomingHttpHeaders = http.IncomingHttpHeaders; -type OutgoingHttpHeaders = http.OutgoingHttpHeaders; +const FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL = + (NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12) || + (NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2) || + NODE_VERSION.major >= 24; export type SentryHttpInstrumentationOptions = InstrumentationConfig & { /** @@ -96,19 +76,19 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { * Hooks for outgoing request spans, called when `createSpansForOutgoingRequests` is enabled. * These mirror the OTEL HttpInstrumentation hooks for backwards compatibility. */ - outgoingRequestHook?: (span: Span, request: http.ClientRequest) => void; - outgoingResponseHook?: (span: Span, response: http.IncomingMessage) => void; + outgoingRequestHook?: (span: Span, request: ClientRequest | HttpClientRequest) => void; + outgoingResponseHook?: (span: Span, response: IncomingMessage | HttpIncomingMessage) => void; outgoingRequestApplyCustomAttributes?: ( span: Span, - request: http.ClientRequest, - response: http.IncomingMessage, + request: HttpClientRequest, + response: HttpIncomingMessage, ) => void; // All options below do not do anything anymore in this instrumentation, and will be removed in the future. // They are only kept here for backwards compatibility - the respective functionality is now handled by the httpServerIntegration/httpServerSpansIntegration. /** - * @depreacted This no longer does anything. + * @deprecated This no longer does anything. */ extractIncomingTraceFromHeader?: boolean; @@ -125,7 +105,7 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { /** * @deprecated This no longer does anything. */ - ignoreSpansForIncomingRequests?: (urlPath: string, request: http.IncomingMessage) => boolean; + ignoreSpansForIncomingRequests?: (urlPath: string, request: IncomingMessage) => boolean; /** * @deprecated This no longer does anything. @@ -146,12 +126,12 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { * @deprecated This no longer does anything. */ instrumentation?: { - requestHook?: (span: Span, req: http.ClientRequest | http.IncomingMessage) => void; - responseHook?: (span: Span, response: http.IncomingMessage | http.ServerResponse) => void; + requestHook?: (span: Span, req: ClientRequest | IncomingMessage) => void; + responseHook?: (span: Span, response: IncomingMessage | ServerResponse) => void; applyCustomAttributesOnSpan?: ( span: Span, - request: http.ClientRequest | http.IncomingMessage, - response: http.IncomingMessage | http.ServerResponse, + request: ClientRequest | IncomingMessage, + response: IncomingMessage | ServerResponse, ) => void; }; @@ -178,64 +158,77 @@ export type SentryHttpInstrumentationOptions = InstrumentationConfig & { * https://github.com/open-telemetry/opentelemetry-js/blob/f8ab5592ddea5cba0a3b33bf8d74f27872c0367f/experimental/packages/opentelemetry-instrumentation-http/src/http.ts */ export class SentryHttpInstrumentation extends InstrumentationBase { - private _propagationDecisionMap: LRUMap; - private _ignoreOutgoingRequestsMap: WeakMap; - public constructor(config: SentryHttpInstrumentationOptions = {}) { super(INSTRUMENTATION_NAME, SDK_VERSION, config); - - this._propagationDecisionMap = new LRUMap(100); - this._ignoreOutgoingRequestsMap = new WeakMap(); } /** @inheritdoc */ public init(): [InstrumentationNodeModuleDefinition, InstrumentationNodeModuleDefinition] { - // We register handlers when either http or https is instrumented - // but we only want to register them once, whichever is loaded first - let hasRegisteredHandlers = false; - - const onHttpClientResponseFinish = ((_data: unknown) => { - const data = _data as { request: http.ClientRequest; response: http.IncomingMessage }; - this._onOutgoingRequestFinish(data.request, data.response); - }) satisfies ChannelListener; - - const onHttpClientRequestError = ((_data: unknown) => { - const data = _data as { request: http.ClientRequest }; - this._onOutgoingRequestFinish(data.request, undefined); - }) satisfies ChannelListener; - - const onHttpClientRequestCreated = ((_data: unknown) => { - const data = _data as { request: http.ClientRequest }; - this._onOutgoingRequestCreated(data.request); - }) satisfies ChannelListener; - - const wrap = (moduleExports: T): T => { - if (hasRegisteredHandlers) { - return moduleExports; - } + const { outgoingRequestApplyCustomAttributes: applyCustomAttributesOnSpan, ...options } = this.getConfig(); + const patchOptions: HttpInstrumentationOptions = { + propagateTrace: options.propagateTraceInOutgoingRequests, + applyCustomAttributesOnSpan, + ...options, + spans: options.createSpansForOutgoingRequests ?? options.spans, + ignoreOutgoingRequests(url, request) { + return ( + isTracingSuppressed(context.active()) || + !!options.ignoreOutgoingRequests?.(url, getRequestOptions(request as ClientRequest)) + ); + }, + outgoingRequestHook(span, request) { + options.outgoingRequestHook?.(span, request); + // We monkey-patch `req.once('response'), which is used to trigger + // the callback of the request, so that it runs in the active context + // eslint-disable-next-line @typescript-eslint/unbound-method, deprecation/deprecation + const originalOnce = request.once; + + const newOnce = new Proxy(originalOnce, { + apply(target, thisArg, args: Parameters) { + const [event] = args; + if (event !== 'response') { + return target.apply(thisArg, args); + } + + const parentContext = context.active(); + const requestContext = trace.setSpan(parentContext, span); + + return context.with(requestContext, () => { + return target.apply(thisArg, args); + }); + }, + }); - hasRegisteredHandlers = true; + // eslint-disable-next-line deprecation/deprecation + request.once = newOnce; + }, + outgoingResponseHook(span, response) { + options.outgoingResponseHook?.(span, response); + context.bind(context.active(), response); + }, + errorMonitor, + }; - subscribe('http.client.response.finish', onHttpClientResponseFinish); + // only generate the subscriber function if we'll actually use it + const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL + ? getHttpClientSubscriptions(patchOptions) + : {}; - // When an error happens, we still want to have a breadcrumb - // In this case, `http.client.response.finish` is not triggered - subscribe('http.client.request.error', onHttpClientRequestError); + // guard because we cover both http and https with the same subscribers + let hasRegisteredHandlers = false; + const sub = onHttpClientRequestCreated + ? (moduleExports: T): T => { + if (!hasRegisteredHandlers && onHttpClientRequestCreated) { + hasRegisteredHandlers = true; + subscribe(HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated); + } + return moduleExports; + } + : undefined; - // NOTE: This channel only exists since Node 22.12+ - // Before that, outgoing requests are not patched - // and trace headers are not propagated, sadly. - if (this.getConfig().propagateTraceInOutgoingRequests || this.getConfig().createSpansForOutgoingRequests) { - subscribe('http.client.request.created', onHttpClientRequestCreated); - } - return moduleExports; - }; + const wrapHttp = sub ?? ((moduleExports: HttpModuleExport) => patchHttpModuleClient(moduleExports, patchOptions)); - const unwrap = (): void => { - unsubscribe('http.client.response.finish', onHttpClientResponseFinish); - unsubscribe('http.client.request.error', onHttpClientRequestError); - unsubscribe('http.client.request.created', onHttpClientRequestCreated); - }; + const wrapHttps = sub ?? ((moduleExports: HttpModuleExport) => patchHttpsModuleClient(moduleExports, patchOptions)); /** * You may be wondering why we register these diagnostics-channel listeners @@ -246,278 +239,8 @@ export class SentryHttpInstrumentation extends InstrumentationBase) { - const [event] = args; - if (event !== 'response') { - return target.apply(thisArg, args); - } - - const parentContext = context.active(); - const requestContext = trace.setSpan(parentContext, span); - - return context.with(requestContext, () => { - return target.apply(thisArg, args); - }); - }, - }); - - // eslint-disable-next-line deprecation/deprecation - request.once = newOnce; - - /** - * Determines if the request has errored or the response has ended/errored. - */ - let responseFinished = false; - - const endSpan = (status: SpanStatus): void => { - if (responseFinished) { - return; - } - responseFinished = true; - - span.setStatus(status); - span.end(); - }; - - request.prependListener('response', response => { - if (request.listenerCount('response') <= 1) { - response.resume(); - } - - context.bind(context.active(), response); - - const additionalAttributes = _getOutgoingRequestEndedSpanData(response); - span.setAttributes(additionalAttributes); - - this.getConfig().outgoingResponseHook?.(span, response); - this.getConfig().outgoingRequestApplyCustomAttributes?.(span, request, response); - - const endHandler = (forceError: boolean = false): void => { - this._diag.debug('outgoingRequest on end()'); - - const status = - // eslint-disable-next-line deprecation/deprecation - forceError || typeof response.statusCode !== 'number' || (response.aborted && !response.complete) - ? { code: SpanStatusCode.ERROR } - : getSpanStatusFromHttpCode(response.statusCode); - - endSpan(status); - }; - - response.on('end', () => { - endHandler(); - }); - response.on(errorMonitor, error => { - this._diag.debug('outgoingRequest on response error()', error); - endHandler(true); - }); - }); - - // Fallback if proper response end handling above fails - request.on('close', () => { - endSpan({ code: SpanStatusCode.UNSET }); - }); - request.on(errorMonitor, error => { - this._diag.debug('outgoingRequest on request error()', error); - endSpan({ code: SpanStatusCode.ERROR }); - }); - - return span; - } - - /** - * This is triggered when an outgoing request finishes. - * It has access to the final request and response objects. - */ - private _onOutgoingRequestFinish(request: http.ClientRequest, response?: http.IncomingMessage): void { - DEBUG_BUILD && debug.log(INSTRUMENTATION_NAME, 'Handling finished outgoing request'); - - const _breadcrumbs = this.getConfig().breadcrumbs; - const breadCrumbsEnabled = typeof _breadcrumbs === 'undefined' ? true : _breadcrumbs; - - // Note: We cannot rely on the map being set by `_onOutgoingRequestCreated`, because that is not run in Node <22 - const shouldIgnore = this._ignoreOutgoingRequestsMap.get(request) ?? this._shouldIgnoreOutgoingRequest(request); - this._ignoreOutgoingRequestsMap.set(request, shouldIgnore); - - if (breadCrumbsEnabled && !shouldIgnore) { - addRequestBreadcrumb(request, response); - } - } - - /** - * This is triggered when an outgoing request is created. - * It creates a span (if enabled) and propagates trace headers within the span's context, - * so downstream services link to the outgoing HTTP span rather than its parent. - */ - private _onOutgoingRequestCreated(request: http.ClientRequest): void { - DEBUG_BUILD && debug.log(INSTRUMENTATION_NAME, 'Handling outgoing request created'); - - const shouldIgnore = this._ignoreOutgoingRequestsMap.get(request) ?? this._shouldIgnoreOutgoingRequest(request); - this._ignoreOutgoingRequestsMap.set(request, shouldIgnore); - - if (shouldIgnore) { - return; - } - - const shouldCreateSpan = this.getConfig().createSpansForOutgoingRequests && (this.getConfig().spans ?? true); - const shouldPropagate = this.getConfig().propagateTraceInOutgoingRequests; - - if (shouldCreateSpan) { - const span = this._startSpanForOutgoingRequest(request); - - // Propagate headers within the span's context so the sentry-trace header - // contains the outgoing span's ID, not the parent span's ID. - // Only do this if the span is recording (has a parent) - otherwise the non-recording - // span would produce all-zero trace IDs instead of using the scope's propagation context. - if (shouldPropagate && span.isRecording()) { - const requestContext = trace.setSpan(context.active(), span); - context.with(requestContext, () => { - addTracePropagationHeadersToOutgoingRequest(request, this._propagationDecisionMap); - }); - } else if (shouldPropagate) { - addTracePropagationHeadersToOutgoingRequest(request, this._propagationDecisionMap); - } - } else if (shouldPropagate) { - addTracePropagationHeadersToOutgoingRequest(request, this._propagationDecisionMap); - } - } - - /** - * Check if the given outgoing request should be ignored. - */ - private _shouldIgnoreOutgoingRequest(request: http.ClientRequest): boolean { - if (isTracingSuppressed(context.active())) { - return true; - } - - const ignoreOutgoingRequests = this.getConfig().ignoreOutgoingRequests; - - if (!ignoreOutgoingRequests) { - return false; - } - - const options = getRequestOptions(request); - const url = getClientRequestUrl(request); - return ignoreOutgoingRequests(url, options); - } -} - -function _getOutgoingRequestSpanData(request: http.ClientRequest): [string, SpanAttributes] { - const url = getClientRequestUrl(request); - - const [name, attributes] = getHttpSpanDetailsFromUrlObject( - parseStringToURLObject(url), - 'client', - 'auto.http.otel.http', - request, - ); - - const userAgent = request.getHeader('user-agent'); - - return [ - name, - { - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'http.client', - 'otel.kind': 'CLIENT', - [ATTR_USER_AGENT_ORIGINAL]: userAgent, - [ATTR_URL_FULL]: url, - 'http.url': url, - 'http.method': request.method, - 'http.target': request.path || '/', - 'net.peer.name': request.host, - 'http.host': request.getHeader('host'), - ...attributes, - }, - ]; -} - -function _getOutgoingRequestEndedSpanData(response: http.IncomingMessage): SpanAttributes { - const { statusCode, statusMessage, httpVersion, socket } = response; - - const transport = httpVersion.toUpperCase() !== 'QUIC' ? 'ip_tcp' : 'ip_udp'; - - const additionalAttributes: SpanAttributes = { - [ATTR_HTTP_RESPONSE_STATUS_CODE]: statusCode, - [ATTR_NETWORK_PROTOCOL_VERSION]: httpVersion, - 'http.flavor': httpVersion, - [ATTR_NETWORK_TRANSPORT]: transport, - 'net.transport': transport, - ['http.status_text']: statusMessage?.toUpperCase(), - 'http.status_code': statusCode, - ...getResponseContentLengthAttributes(response), - }; - - if (socket) { - const { remoteAddress, remotePort } = socket; - - additionalAttributes[ATTR_NETWORK_PEER_ADDRESS] = remoteAddress; - additionalAttributes[ATTR_NETWORK_PEER_PORT] = remotePort; - additionalAttributes['net.peer.ip'] = remoteAddress; - additionalAttributes['net.peer.port'] = remotePort; - } - - return additionalAttributes; -} - -function getResponseContentLengthAttributes(response: http.IncomingMessage): SpanAttributes { - const length = getContentLength(response.headers); - if (length == null) { - return {}; - } - - if (isCompressed(response.headers)) { - // eslint-disable-next-line deprecation/deprecation - return { [SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH]: length }; - } else { - // eslint-disable-next-line deprecation/deprecation - return { [SEMATTRS_HTTP_RESPONSE_CONTENT_LENGTH_UNCOMPRESSED]: length }; - } -} - -function getContentLength(headers: http.OutgoingHttpHeaders | http.IncomingHttpHeaders): number | undefined { - const contentLengthHeader = headers['content-length']; - if (typeof contentLengthHeader === 'number') { - return contentLengthHeader; - } - if (typeof contentLengthHeader !== 'string') { - return undefined; - } - - const contentLength = parseInt(contentLengthHeader, 10); - if (isNaN(contentLength)) { - return undefined; - } - - return contentLength; -} - -function isCompressed(headers: OutgoingHttpHeaders | IncomingHttpHeaders): boolean { - const encoding = headers['content-encoding']; - - return !!encoding && encoding !== 'identity'; } diff --git a/packages/node-core/src/integrations/http/httpServerIntegration.ts b/packages/node-core/src/integrations/http/httpServerIntegration.ts index 986be8d4c8ff..1c08e9f4f16e 100644 --- a/packages/node-core/src/integrations/http/httpServerIntegration.ts +++ b/packages/node-core/src/integrations/http/httpServerIntegration.ts @@ -4,7 +4,7 @@ import type { EventEmitter } from 'node:events'; import type { IncomingMessage, RequestOptions, Server, ServerResponse } from 'node:http'; import type { Socket } from 'node:net'; import { context, createContextKey, propagation } from '@opentelemetry/api'; -import type { AggregationCounts, Client, Integration, IntegrationFn, Scope } from '@sentry/core'; +import type { AggregationCounts, Client, HttpIncomingMessage, Integration, IntegrationFn, Scope } from '@sentry/core'; import { _INTERNAL_safeMathRandom, addNonEnumerableProperty, @@ -30,7 +30,7 @@ interface WeakRefImpl { } type StartSpanCallback = (next: () => boolean) => boolean; -type RequestWithOptionalStartSpanCallback = IncomingMessage & { +type RequestWithOptionalStartSpanCallback = HttpIncomingMessage & { _startSpanCallback?: WeakRefImpl; }; diff --git a/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts b/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts index 7909482a5923..3d70387df415 100644 --- a/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts +++ b/packages/node-core/src/integrations/http/httpServerSpansIntegration.ts @@ -1,5 +1,5 @@ import { errorMonitor } from 'node:events'; -import type { ClientRequest, IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'node:http'; +import type { IncomingHttpHeaders } from 'node:http'; import { context, SpanKind, trace } from '@opentelemetry/api'; import type { RPCMetadata } from '@opentelemetry/core'; import { getRPCMetadata, isTracingSuppressed, RPCType, setRPCMetadata } from '@opentelemetry/core'; @@ -11,7 +11,17 @@ import { SEMATTRS_NET_HOST_PORT, SEMATTRS_NET_PEER_IP, } from '@opentelemetry/semantic-conventions'; -import type { Event, Integration, IntegrationFn, Span, SpanAttributes, SpanStatus } from '@sentry/core'; +import type { + Event, + HttpClientRequest, + HttpIncomingMessage, + HttpServerResponse, + Integration, + IntegrationFn, + Span, + SpanAttributes, + SpanStatus, +} from '@sentry/core'; import { debug, getIsolationScope, @@ -43,7 +53,7 @@ export interface HttpServerSpansIntegrationOptions { * The `request` param contains the original {@type IncomingMessage} object of the incoming request. * You can use it to filter on additional properties like method, headers, etc. */ - ignoreIncomingRequests?: (urlPath: string, request: IncomingMessage) => boolean; + ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean; /** * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc. @@ -66,12 +76,12 @@ export interface HttpServerSpansIntegrationOptions { * @deprecated This is deprecated in favor of `incomingRequestSpanHook`. */ instrumentation?: { - requestHook?: (span: Span, req: ClientRequest | IncomingMessage) => void; - responseHook?: (span: Span, response: IncomingMessage | ServerResponse) => void; + requestHook?: (span: Span, req: HttpClientRequest | HttpIncomingMessage) => void; + responseHook?: (span: Span, response: HttpIncomingMessage | HttpServerResponse) => void; applyCustomAttributesOnSpan?: ( span: Span, - request: ClientRequest | IncomingMessage, - response: IncomingMessage | ServerResponse, + request: HttpClientRequest | HttpIncomingMessage, + response: HttpIncomingMessage | HttpServerResponse, ) => void; }; @@ -79,7 +89,7 @@ export interface HttpServerSpansIntegrationOptions { * A hook that can be used to mutate the span for incoming requests. * This is triggered after the span is created, but before it is recorded. */ - onSpanCreated?: (span: Span, request: IncomingMessage, response: ServerResponse) => void; + onSpanCreated?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void; } const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions = {}) => { @@ -106,8 +116,8 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions client.on('httpServerRequest', (_request, _response, normalizedRequest) => { // Type-casting this here because we do not want to put the node types into core - const request = _request as IncomingMessage; - const response = _response as ServerResponse; + const request = _request as HttpIncomingMessage; + const response = _response as HttpServerResponse; const startSpan = (next: () => boolean): boolean => { if ( @@ -127,7 +137,7 @@ const _httpServerSpansIntegration = ((options: HttpServerSpansIntegrationOptions const userAgent = headers['user-agent']; const ips = headers['x-forwarded-for']; const httpVersion = request.httpVersion; - const host = headers.host; + const host = headers.host as string | undefined; const hostname = host?.replace(/^(.*)(:[0-9]{1,5})/, '$1') || 'localhost'; const tracer = client.tracer; @@ -264,7 +274,7 @@ export const httpServerSpansIntegration = _httpServerSpansIntegration as ( processEvent: (event: Event) => Event | null; }; -function isKnownPrefetchRequest(req: IncomingMessage): boolean { +function isKnownPrefetchRequest(req: HttpIncomingMessage): boolean { // Currently only handles Next.js prefetch requests but may check other frameworks in the future. return req.headers['next-router-prefetch'] === '1'; } @@ -290,13 +300,13 @@ export function isStaticAssetRequest(urlPath: string): boolean { } function shouldIgnoreSpansForIncomingRequest( - request: IncomingMessage, + request: HttpIncomingMessage, { ignoreStaticAssets, ignoreIncomingRequests, }: { ignoreStaticAssets?: boolean; - ignoreIncomingRequests?: (urlPath: string, request: IncomingMessage) => boolean; + ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean; }, ): boolean { if (isTracingSuppressed(context.active())) { @@ -325,7 +335,7 @@ function shouldIgnoreSpansForIncomingRequest( return false; } -function getRequestContentLengthAttribute(request: IncomingMessage): SpanAttributes { +function getRequestContentLengthAttribute(request: HttpIncomingMessage): SpanAttributes { const length = getContentLength(request.headers); if (length == null) { return {}; @@ -358,7 +368,10 @@ function isCompressed(headers: IncomingHttpHeaders): boolean { return !!encoding && encoding !== 'identity'; } -function getIncomingRequestAttributesOnResponse(request: IncomingMessage, response: ServerResponse): SpanAttributes { +function getIncomingRequestAttributesOnResponse( + request: HttpIncomingMessage, + response: HttpServerResponse, +): SpanAttributes { // take socket from the request, // since it may be detached from the response object in keep-alive mode const { socket } = request; diff --git a/packages/node-core/src/integrations/http/index.ts b/packages/node-core/src/integrations/http/index.ts index 34cb86704415..a59186875c76 100644 --- a/packages/node-core/src/integrations/http/index.ts +++ b/packages/node-core/src/integrations/http/index.ts @@ -1,4 +1,5 @@ -import type { IncomingMessage, RequestOptions } from 'node:http'; +import type { RequestOptions } from 'node:http'; +import type { HttpIncomingMessage } from '@sentry/core'; import { defineIntegration } from '@sentry/core'; import { generateInstrumentOnce } from '../../otel/instrument'; import type { NodeClient } from '../../sdk/client'; @@ -73,7 +74,7 @@ interface HttpOptions { * The `request` param contains the original {@type IncomingMessage} object of the incoming request. * You can use it to filter on additional properties like method, headers, etc. */ - ignoreIncomingRequests?: (urlPath: string, request: IncomingMessage) => boolean; + ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean; /** * Do not capture spans for incoming HTTP requests with the given status codes. diff --git a/packages/node-core/src/integrations/http/outgoing-requests.ts b/packages/node-core/src/integrations/http/outgoing-requests.ts deleted file mode 100644 index b505904906fc..000000000000 --- a/packages/node-core/src/integrations/http/outgoing-requests.ts +++ /dev/null @@ -1,6 +0,0 @@ -export { - addRequestBreadcrumb, - addTracePropagationHeadersToOutgoingRequest, - getClientRequestUrl, - getRequestOptions, -} from '../../utils/outgoingHttpRequest'; diff --git a/packages/node-core/src/light/asyncLocalStorageStrategy.ts b/packages/node-core/src/light/asyncLocalStorageStrategy.ts index 1d6f3f413e59..00a7939d664f 100644 --- a/packages/node-core/src/light/asyncLocalStorageStrategy.ts +++ b/packages/node-core/src/light/asyncLocalStorageStrategy.ts @@ -1,6 +1,11 @@ import { AsyncLocalStorage } from 'node:async_hooks'; import type { Scope } from '@sentry/core'; -import { getDefaultCurrentScope, getDefaultIsolationScope, setAsyncContextStrategy } from '@sentry/core'; +import { + getDefaultCurrentScope, + getDefaultIsolationScope, + setAsyncContextStrategy, + SUPPRESS_TRACING_KEY, +} from '@sentry/core'; /** * Sets the async context strategy to use AsyncLocalStorage. @@ -62,7 +67,7 @@ export function setAsyncLocalStorageAsyncContextStrategy(): void { // In contrast to the browser, we can rely on async context isolation here function suppressTracing(callback: () => T): T { return withScope(scope => { - scope.setSDKProcessingMetadata({ __SENTRY_SUPPRESS_TRACING__: true }); + scope.setSDKProcessingMetadata({ [SUPPRESS_TRACING_KEY]: true }); return callback(); }); } diff --git a/packages/node-core/src/light/integrations/httpIntegration.ts b/packages/node-core/src/light/integrations/httpIntegration.ts index 0f3d6f5c5cc4..d13f908e1b1f 100644 --- a/packages/node-core/src/light/integrations/httpIntegration.ts +++ b/packages/node-core/src/light/integrations/httpIntegration.ts @@ -1,30 +1,35 @@ -import type { ChannelListener } from 'node:diagnostics_channel'; import { subscribe } from 'node:diagnostics_channel'; -import type { ClientRequest, IncomingMessage, RequestOptions, Server } from 'node:http'; -import type { Integration, IntegrationFn } from '@sentry/core'; +import type { RequestOptions } from 'node:http'; +import type { HttpClientRequest, HttpIncomingMessage, Integration, IntegrationFn } from '@sentry/core'; import { + addOutgoingRequestBreadcrumb, continueTrace, debug, generateSpanId, getCurrentScope, + getHttpClientSubscriptions, getIsolationScope, + HTTP_ON_CLIENT_REQUEST, httpRequestToRequestData, - LRUMap, stripUrlQueryAndFragment, + SUPPRESS_TRACING_KEY, withIsolationScope, } from '@sentry/core'; +import type { ClientRequest, IncomingMessage, Server } from 'node:http'; import { DEBUG_BUILD } from '../../debug-build'; import { patchRequestToCaptureBody } from '../../utils/captureRequestBody'; -import { - addRequestBreadcrumb, - addTracePropagationHeadersToOutgoingRequest, - getClientRequestUrl, - getRequestOptions, -} from '../../utils/outgoingHttpRequest'; +import { getClientRequestUrl, getRequestOptions } from '../../utils/outgoingHttpRequest'; import type { LightNodeClient } from '../client'; +import { errorMonitor } from 'node:events'; +import { NODE_VERSION } from '../../nodeVersion'; const INTEGRATION_NAME = 'Http'; +const FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL = + (NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12) || + (NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2) || + NODE_VERSION.major >= 24; + // We keep track of emit functions we wrapped, to avoid double wrapping const wrappedEmitFns = new WeakSet(); @@ -83,6 +88,8 @@ export interface HttpIntegrationOptions { const _httpIntegration = ((options: HttpIntegrationOptions = {}) => { const _options = { + ...options, + sessions: false, maxRequestBodySize: options.maxRequestBodySize ?? 'medium', ignoreRequestBody: options.ignoreRequestBody, breadcrumbs: options.breadcrumbs ?? true, @@ -90,40 +97,74 @@ const _httpIntegration = ((options: HttpIntegrationOptions = {}) => { ignoreOutgoingRequests: options.ignoreOutgoingRequests, }; - const propagationDecisionMap = new LRUMap(100); - const ignoreOutgoingRequestsMap = new WeakMap(); - return { name: INTEGRATION_NAME, setupOnce() { - const onHttpServerRequestStart = ((_data: unknown) => { + const onHttpServerRequestStart = (_data: unknown) => { const data = _data as { server: Server }; instrumentServer(data.server, _options); - }) satisfies ChannelListener; - - const onHttpClientRequestCreated = ((_data: unknown) => { - const data = _data as { request: ClientRequest }; - onOutgoingRequestCreated(data.request, _options, propagationDecisionMap, ignoreOutgoingRequestsMap); - }) satisfies ChannelListener; - - const onHttpClientResponseFinish = ((_data: unknown) => { - const data = _data as { request: ClientRequest; response: IncomingMessage }; - onOutgoingRequestFinish(data.request, data.response, _options, ignoreOutgoingRequestsMap); - }) satisfies ChannelListener; - - const onHttpClientRequestError = ((_data: unknown) => { - const data = _data as { request: ClientRequest }; - onOutgoingRequestFinish(data.request, undefined, _options, ignoreOutgoingRequestsMap); - }) satisfies ChannelListener; + }; + + const { ignoreOutgoingRequests } = _options; + + const { [HTTP_ON_CLIENT_REQUEST]: onHttpClientRequestCreated } = getHttpClientSubscriptions({ + breadcrumbs: _options.breadcrumbs, + propagateTrace: _options.tracePropagation, + ignoreOutgoingRequests: ignoreOutgoingRequests + ? (url, request) => ignoreOutgoingRequests(url, getRequestOptions(request as ClientRequest)) + : undefined, + // No spans in light mode + spans: false, + errorMonitor, + }); subscribe('http.server.request.start', onHttpServerRequestStart); - subscribe('http.client.request.created', onHttpClientRequestCreated); - subscribe('http.client.response.finish', onHttpClientResponseFinish); - subscribe('http.client.request.error', onHttpClientRequestError); + + // Subscribe on the request creation in node versions that support it + subscribe(HTTP_ON_CLIENT_REQUEST, onHttpClientRequestCreated); + + // fall back to just doing breadcrumbs on the request.end() channel + // if we do not have earlier access to the request object at creation + // time. The http.client.request.error channel is only available on + // the same node versions as client.request.created, so no help. + if (_options.breadcrumbs && !FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL) { + subscribe('http.client.response.finish', (data: unknown) => { + const { request, response } = data as { + request: HttpClientRequest; + response: HttpIncomingMessage; + }; + onOutgoingResponseFinish(request, response, _options); + }); + } }, }; }) satisfies IntegrationFn; +function onOutgoingResponseFinish( + request: HttpClientRequest, + response: HttpIncomingMessage | undefined, + options: { + breadcrumbs: boolean; + ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean; + }, +): void { + if (!options.breadcrumbs) { + return; + } + // Check if tracing is suppressed (e.g. for Sentry's own transport requests) + if (getCurrentScope().getScopeData().sdkProcessingMetadata[SUPPRESS_TRACING_KEY]) { + return; + } + const { ignoreOutgoingRequests } = options; + if (ignoreOutgoingRequests) { + const url = getClientRequestUrl(request as ClientRequest); + if (ignoreOutgoingRequests(url, getRequestOptions(request as ClientRequest))) { + return; + } + } + addOutgoingRequestBreadcrumb(request, response); +} + /** * This integration handles incoming and outgoing HTTP requests in light mode (without OpenTelemetry). * @@ -221,65 +262,3 @@ function instrumentServer( wrappedEmitFns.add(newEmit); server.emit = newEmit; } - -function onOutgoingRequestCreated( - request: ClientRequest, - options: { tracePropagation: boolean; ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean }, - propagationDecisionMap: LRUMap, - ignoreOutgoingRequestsMap: WeakMap, -): void { - const shouldIgnore = shouldIgnoreOutgoingRequest(request, options); - ignoreOutgoingRequestsMap.set(request, shouldIgnore); - - if (shouldIgnore) { - return; - } - - if (options.tracePropagation) { - addTracePropagationHeadersToOutgoingRequest(request, propagationDecisionMap); - } -} - -function onOutgoingRequestFinish( - request: ClientRequest, - response: IncomingMessage | undefined, - options: { - breadcrumbs: boolean; - ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean; - }, - ignoreOutgoingRequestsMap: WeakMap, -): void { - if (!options.breadcrumbs) { - return; - } - - // Note: We cannot rely on the map being set by `onOutgoingRequestCreated`, because that channel - // only exists since Node 22 - const shouldIgnore = ignoreOutgoingRequestsMap.get(request) ?? shouldIgnoreOutgoingRequest(request, options); - - if (shouldIgnore) { - return; - } - - addRequestBreadcrumb(request, response); -} - -/** Check if the given outgoing request should be ignored. */ -function shouldIgnoreOutgoingRequest( - request: ClientRequest, - options: { ignoreOutgoingRequests?: (url: string, request: RequestOptions) => boolean }, -): boolean { - // Check if tracing is suppressed (e.g. for Sentry's own transport requests) - if (getCurrentScope().getScopeData().sdkProcessingMetadata.__SENTRY_SUPPRESS_TRACING__) { - return true; - } - - const { ignoreOutgoingRequests } = options; - - if (!ignoreOutgoingRequests) { - return false; - } - - const url = getClientRequestUrl(request); - return ignoreOutgoingRequests(url, getRequestOptions(request)); -} diff --git a/packages/node-core/src/utils/outgoingHttpRequest.ts b/packages/node-core/src/utils/outgoingHttpRequest.ts index 34624900b472..8f1fa4f60658 100644 --- a/packages/node-core/src/utils/outgoingHttpRequest.ts +++ b/packages/node-core/src/utils/outgoingHttpRequest.ts @@ -1,145 +1,4 @@ -import type { LRUMap, SanitizedRequestData } from '@sentry/core'; -import { - addBreadcrumb, - debug, - getBreadcrumbLogLevelFromHttpStatusCode, - getClient, - getSanitizedUrlString, - getTraceData, - isError, - parseUrl, - shouldPropagateTraceForUrl, -} from '@sentry/core'; -import type { ClientRequest, IncomingMessage, RequestOptions } from 'http'; -import { DEBUG_BUILD } from '../debug-build'; -import { mergeBaggageHeaders } from './baggage'; - -const LOG_PREFIX = '@sentry/instrumentation-http'; - -/** Add a breadcrumb for outgoing requests. */ -export function addRequestBreadcrumb(request: ClientRequest, response: IncomingMessage | undefined): void { - const data = getBreadcrumbData(request); - - const statusCode = response?.statusCode; - const level = getBreadcrumbLogLevelFromHttpStatusCode(statusCode); - - addBreadcrumb( - { - category: 'http', - data: { - status_code: statusCode, - ...data, - }, - type: 'http', - level, - }, - { - event: 'response', - request, - response, - }, - ); -} - -/** - * Add trace propagation headers to an outgoing request. - * This must be called _before_ the request is sent! - */ -// eslint-disable-next-line complexity -export function addTracePropagationHeadersToOutgoingRequest( - request: ClientRequest, - propagationDecisionMap: LRUMap, -): void { - const url = getClientRequestUrl(request); - - const { tracePropagationTargets, propagateTraceparent } = getClient()?.getOptions() || {}; - const headersToAdd = shouldPropagateTraceForUrl(url, tracePropagationTargets, propagationDecisionMap) - ? getTraceData({ propagateTraceparent }) - : undefined; - - if (!headersToAdd) { - return; - } - - const { 'sentry-trace': sentryTrace, baggage, traceparent } = headersToAdd; - - const hasExistingSentryTraceHeader = !!request.getHeader('sentry-trace'); - - if (hasExistingSentryTraceHeader) { - return; - } - - if (sentryTrace) { - try { - request.setHeader('sentry-trace', sentryTrace); - DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added sentry-trace header to outgoing request'); - } catch (error) { - DEBUG_BUILD && - debug.error( - LOG_PREFIX, - 'Failed to add sentry-trace header to outgoing request:', - isError(error) ? error.message : 'Unknown error', - ); - } - } - - if (traceparent && !request.getHeader('traceparent')) { - try { - request.setHeader('traceparent', traceparent); - DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added traceparent header to outgoing request'); - } catch (error) { - DEBUG_BUILD && - debug.error( - LOG_PREFIX, - 'Failed to add traceparent header to outgoing request:', - isError(error) ? error.message : 'Unknown error', - ); - } - } - - if (baggage) { - const existingBaggage = request.getHeader('baggage'); - const newBaggage = mergeBaggageHeaders(existingBaggage, baggage); - if (newBaggage) { - try { - request.setHeader('baggage', newBaggage); - DEBUG_BUILD && debug.log(LOG_PREFIX, 'Added baggage header to outgoing request'); - } catch (error) { - DEBUG_BUILD && - debug.error( - LOG_PREFIX, - 'Failed to add baggage header to outgoing request:', - isError(error) ? error.message : 'Unknown error', - ); - } - } - } -} - -function getBreadcrumbData(request: ClientRequest): Partial { - try { - // `request.host` does not contain the port, but the host header does - const host = request.getHeader('host') || request.host; - const url = new URL(request.path, `${request.protocol}//${host}`); - const parsedUrl = parseUrl(url.toString()); - - const data: Partial = { - url: getSanitizedUrlString(parsedUrl), - 'http.method': request.method || 'GET', - }; - - if (parsedUrl.search) { - data['http.query'] = parsedUrl.search; - } - if (parsedUrl.hash) { - data['http.fragment'] = parsedUrl.hash; - } - - return data; - } catch { - return {}; - } -} +import type { ClientRequest, RequestOptions } from 'http'; /** Convert an outgoing request to request options. */ export function getRequestOptions(request: ClientRequest): RequestOptions { diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index 3e38c12f0c4b..29d59dff96a6 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,38 +1,24 @@ -import type { ClientRequest, IncomingMessage, RequestOptions, ServerResponse } from 'node:http'; -import { diag } from '@opentelemetry/api'; -import type { HttpInstrumentationConfig } from '@opentelemetry/instrumentation-http'; -import { HttpInstrumentation } from '@opentelemetry/instrumentation-http'; -import type { Span } from '@sentry/core'; -import { - defineIntegration, - getClient, - hasSpansEnabled, - SEMANTIC_ATTRIBUTE_URL_FULL, - stripDataUrlContent, -} from '@sentry/core'; -import type { HTTPModuleRequestIncomingMessage, NodeClient, SentryHttpInstrumentationOptions } from '@sentry/node-core'; +import type { RequestOptions } from 'node:http'; +import type { HttpClientRequest, HttpIncomingMessage, HttpServerResponse, Span } from '@sentry/core'; +import { defineIntegration, hasSpansEnabled, SEMANTIC_ATTRIBUTE_URL_FULL, stripDataUrlContent } from '@sentry/core'; +import type { + NodeClient, + SentryHttpInstrumentationOptions, + HttpServerIntegrationOptions, + HttpServerSpansIntegrationOptions, +} from '@sentry/node-core'; import { - addOriginToSpan, generateInstrumentOnce, getRequestUrl, httpServerIntegration, httpServerSpansIntegration, - NODE_VERSION, SentryHttpInstrumentation, } from '@sentry/node-core'; -import type { NodeClientOptions } from '../types'; const INTEGRATION_NAME = 'Http'; -const INSTRUMENTATION_NAME = '@opentelemetry_sentry-patched/instrumentation-http'; - -// The `http.client.request.created` diagnostics channel, needed for trace propagation, -// was added in Node 22.12.0 (backported from 23.2.0). Earlier 22.x versions don't have it. -const FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL = - (NODE_VERSION.major === 22 && NODE_VERSION.minor >= 12) || - (NODE_VERSION.major === 23 && NODE_VERSION.minor >= 2) || - NODE_VERSION.major >= 24; - +// TODO(v11): Consolidate all the various HTTP integration options into one, +// and deprecate the duplicated and aliased options. interface HttpOptions { /** * Whether breadcrumbs should be recorded for outgoing requests. @@ -97,13 +83,13 @@ interface HttpOptions { * The `request` param contains the original {@type IncomingMessage} object of the incoming request. * You can use it to filter on additional properties like method, headers, etc. */ - ignoreIncomingRequests?: (urlPath: string, request: IncomingMessage) => boolean; + ignoreIncomingRequests?: (urlPath: string, request: HttpIncomingMessage) => boolean; /** * A hook that can be used to mutate the span for incoming requests. * This is triggered after the span is created, but before it is recorded. */ - incomingRequestSpanHook?: (span: Span, request: IncomingMessage, response: ServerResponse) => void; + incomingRequestSpanHook?: (span: Span, request: HttpIncomingMessage, response: HttpServerResponse) => void; /** * Whether to automatically ignore common static asset requests like favicon.ico, robots.txt, etc. @@ -157,12 +143,12 @@ interface HttpOptions { * Additional instrumentation options that are passed to the underlying HttpInstrumentation. */ instrumentation?: { - requestHook?: (span: Span, req: ClientRequest | HTTPModuleRequestIncomingMessage) => void; - responseHook?: (span: Span, response: HTTPModuleRequestIncomingMessage | ServerResponse) => void; + requestHook?: (span: Span, req: HttpIncomingMessage | HttpClientRequest) => void; + responseHook?: (span: Span, response: HttpIncomingMessage | HttpServerResponse) => void; applyCustomAttributesOnSpan?: ( span: Span, - request: ClientRequest | HTTPModuleRequestIncomingMessage, - response: HTTPModuleRequestIncomingMessage | ServerResponse, + request: HttpIncomingMessage | HttpClientRequest, + response: HttpIncomingMessage | HttpServerResponse, ) => void; }; } @@ -174,65 +160,6 @@ export const instrumentSentryHttp = generateInstrumentOnce(INTEGRATION_NAME, config => { - const instrumentation = new HttpInstrumentation({ - ...config, - // This is hard-coded and can never be overridden by the user - disableIncomingRequestInstrumentation: true, - }); - - // We want to update the logger namespace so we can better identify what is happening here - try { - instrumentation['_diag'] = diag.createComponentLogger({ - namespace: INSTRUMENTATION_NAME, - }); - // @ts-expect-error We are writing a read-only property here... - instrumentation.instrumentationName = INSTRUMENTATION_NAME; - } catch { - // ignore errors here... - } - - // The OTel HttpInstrumentation (>=0.213.0) has a guard (`_httpPatched`/`_httpsPatched`) - // that prevents patching `http`/`https` when loaded by both CJS `require()` and ESM `import`. - // In environments like AWS Lambda, the runtime loads `http` via CJS first (for the Runtime API), - // and then the user's ESM handler imports `node:http`. The guard blocks ESM patching after CJS, - // which breaks HTTP spans for ESM handlers. We disable this guard to allow both to be patched. - // TODO(andrei): Remove once https://github.com/open-telemetry/opentelemetry-js/issues/6489 is fixed. - try { - const noopDescriptor = { get: () => false, set: () => {} }; - Object.defineProperty(instrumentation, '_httpPatched', noopDescriptor); - Object.defineProperty(instrumentation, '_httpsPatched', noopDescriptor); - } catch { - // ignore errors here... - } - - return instrumentation; -}); - -/** Exported only for tests. */ -export function _shouldUseOtelHttpInstrumentation( - options: HttpOptions, - clientOptions: Partial = {}, -): boolean { - // If `spans` is passed in, it takes precedence - // Else, we by default emit spans, unless `skipOpenTelemetrySetup` is set to `true` or spans are not enabled - if (typeof options.spans === 'boolean') { - return options.spans; - } - - if (clientOptions.skipOpenTelemetrySetup) { - return false; - } - - // IMPORTANT: We only disable span instrumentation when spans are not enabled _and_ we are on a Node version - // that fully supports the necessary diagnostics channels for trace propagation - if (!hasSpansEnabled(clientOptions) && FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL) { - return false; - } - - return true; -} - /** * The http integration instruments Node's internal http and https modules. * It creates breadcrumbs and spans for outgoing HTTP requests which will be attached to the currently active span. @@ -240,27 +167,26 @@ export function _shouldUseOtelHttpInstrumentation( export const httpIntegration = defineIntegration((options: HttpOptions = {}) => { const spans = options.spans ?? true; const disableIncomingRequestSpans = options.disableIncomingRequestSpans; + const enableServerSpans = spans && !disableIncomingRequestSpans; const serverOptions = { sessions: options.trackIncomingRequestsAsSessions, sessionFlushingDelayMS: options.sessionFlushingDelayMS, ignoreRequestBody: options.ignoreIncomingRequestBody, maxRequestBodySize: options.maxIncomingRequestBodySize, - } satisfies Parameters[0]; + } satisfies HttpServerIntegrationOptions; - const serverSpansOptions = { + const serverSpansOptions: HttpServerSpansIntegrationOptions = { ignoreIncomingRequests: options.ignoreIncomingRequests, ignoreStaticAssets: options.ignoreStaticAssets, ignoreStatusCodes: options.dropSpansForIncomingRequestStatusCodes, instrumentation: options.instrumentation, onSpanCreated: options.incomingRequestSpanHook, - } satisfies Parameters[0]; + }; const server = httpServerIntegration(serverOptions); const serverSpans = httpServerSpansIntegration(serverSpansOptions); - const enableServerSpans = spans && !disableIncomingRequestSpans; - return { name: INTEGRATION_NAME, setup(client: NodeClient) { @@ -271,99 +197,42 @@ export const httpIntegration = defineIntegration((options: HttpOptions = {}) => } }, setupOnce() { - const clientOptions = (getClient()?.getOptions() || {}) satisfies Partial; - const useOtelHttpInstrumentation = _shouldUseOtelHttpInstrumentation(options, clientOptions); - server.setupOnce(); - const sentryHttpInstrumentationOptions = { + const sentryHttpInstrumentationOptions: SentryHttpInstrumentationOptions = { breadcrumbs: options.breadcrumbs, - propagateTraceInOutgoingRequests: - typeof options.tracePropagation === 'boolean' - ? options.tracePropagation - : FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL || !useOtelHttpInstrumentation, - createSpansForOutgoingRequests: FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL, spans: options.spans, + propagateTraceInOutgoingRequests: options.tracePropagation ?? true, + createSpansForOutgoingRequests: options.spans, ignoreOutgoingRequests: options.ignoreOutgoingRequests, - outgoingRequestHook: (span: Span, request: ClientRequest) => { + outgoingRequestHook: (span: Span, request: HttpClientRequest) => { // Sanitize data URLs to prevent long base64 strings in span attributes const url = getRequestUrl(request); if (url.startsWith('data:')) { const sanitizedUrl = stripDataUrlContent(url); + // TODO(v11): Update these to the Sentry semantic attributes. + // https://getsentry.github.io/sentry-conventions/attributes/ span.setAttribute('http.url', sanitizedUrl); span.setAttribute(SEMANTIC_ATTRIBUTE_URL_FULL, sanitizedUrl); span.updateName(`${request.method || 'GET'} ${sanitizedUrl}`); } - options.instrumentation?.requestHook?.(span, request); }, outgoingResponseHook: options.instrumentation?.responseHook, outgoingRequestApplyCustomAttributes: options.instrumentation?.applyCustomAttributesOnSpan, - } satisfies SentryHttpInstrumentationOptions; + }; - // This is Sentry-specific instrumentation for outgoing request breadcrumbs & trace propagation + // This is Sentry-specific instrumentation for outgoing request + // breadcrumbs & trace propagation. It uses the diagnostic channels on + // node versions that support it, falling back to monkey-patching when + // needed. instrumentSentryHttp(sentryHttpInstrumentationOptions); - - // This is the "regular" OTEL instrumentation that emits outgoing request spans - if (useOtelHttpInstrumentation) { - const instrumentationConfig = getConfigWithDefaults(options); - instrumentOtelHttp(instrumentationConfig); - } }, processEvent(event) { - // Note: We always run this, even if spans are disabled - // The reason being that e.g. the remix integration disables span creation here but still wants to use the ignore status codes option + // Always run this, even if spans are disabled + // The reason being that e.g. the remix integration disables span + // creation here but still wants to use the ignore status codes option return serverSpans.processEvent(event); }, }; }); - -function getConfigWithDefaults(options: Partial = {}): HttpInstrumentationConfig { - const instrumentationConfig = { - // This is handled by the SentryHttpInstrumentation on Node 22+ - disableOutgoingRequestInstrumentation: FULLY_SUPPORTS_HTTP_DIAGNOSTICS_CHANNEL, - - ignoreOutgoingRequestHook: request => { - const url = getRequestUrl(request); - - if (!url) { - return false; - } - - const _ignoreOutgoingRequests = options.ignoreOutgoingRequests; - if (_ignoreOutgoingRequests?.(url, request)) { - return true; - } - - return false; - }, - - requireParentforOutgoingSpans: false, - requestHook: (span, req) => { - addOriginToSpan(span, 'auto.http.otel.http'); - - // Sanitize data URLs to prevent long base64 strings in span attributes - const url = getRequestUrl(req as ClientRequest); - if (url.startsWith('data:')) { - const sanitizedUrl = stripDataUrlContent(url); - span.setAttribute('http.url', sanitizedUrl); - span.setAttribute(SEMANTIC_ATTRIBUTE_URL_FULL, sanitizedUrl); - span.updateName(`${(req as ClientRequest).method || 'GET'} ${sanitizedUrl}`); - } - - options.instrumentation?.requestHook?.(span, req); - }, - responseHook: (span, res) => { - options.instrumentation?.responseHook?.(span, res); - }, - applyCustomAttributesOnSpan: ( - span: Span, - request: ClientRequest | HTTPModuleRequestIncomingMessage, - response: HTTPModuleRequestIncomingMessage | ServerResponse, - ) => { - options.instrumentation?.applyCustomAttributesOnSpan?.(span, request, response); - }, - } satisfies HttpInstrumentationConfig; - - return instrumentationConfig; -} diff --git a/packages/node/src/integrations/tracing/index.ts b/packages/node/src/integrations/tracing/index.ts index dcd2efa5595c..944d762f26b4 100644 --- a/packages/node/src/integrations/tracing/index.ts +++ b/packages/node/src/integrations/tracing/index.ts @@ -1,5 +1,5 @@ import type { Integration } from '@sentry/core'; -import { instrumentOtelHttp, instrumentSentryHttp } from '../http'; +import { instrumentSentryHttp } from '../http'; import { amqplibIntegration, instrumentAmqplib } from './amqplib'; import { anthropicAIIntegration, instrumentAnthropicAi } from './anthropic-ai'; import { connectIntegration, instrumentConnect } from './connect'; @@ -72,7 +72,6 @@ export function getAutoPerformanceIntegrations(): Integration[] { export function getOpenTelemetryInstrumentationToPreload(): (((options?: any) => void) & { id: string })[] { return [ instrumentSentryHttp, - instrumentOtelHttp, instrumentExpress, instrumentConnect, instrumentFastify, diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts deleted file mode 100644 index d02bc12393c6..000000000000 --- a/packages/node/test/integrations/http.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { describe, expect, it } from 'vitest'; -import { _shouldUseOtelHttpInstrumentation } from '../../src/integrations/http'; -import { conditionalTest } from '../helpers/conditional'; - -describe('httpIntegration', () => { - describe('_shouldInstrumentSpans', () => { - it.each([ - [{ spans: true }, {}, true], - [{ spans: false }, {}, false], - [{ spans: true }, { skipOpenTelemetrySetup: true }, true], - [{ spans: false }, { skipOpenTelemetrySetup: true }, false], - [{}, { skipOpenTelemetrySetup: true }, false], - [{}, { tracesSampleRate: 0, skipOpenTelemetrySetup: true }, false], - [{}, { tracesSampleRate: 0 }, true], - ])('returns the correct value for options=%j and clientOptions=%j', (options, clientOptions, expected) => { - const actual = _shouldUseOtelHttpInstrumentation(options, clientOptions); - expect(actual).toBe(expected); - }); - - conditionalTest({ min: 22 })('returns false without tracesSampleRate on Node >=22.12', () => { - const actual = _shouldUseOtelHttpInstrumentation({}, {}); - expect(actual).toBe(false); - }); - - conditionalTest({ max: 21 })('returns true without tracesSampleRate on Node <22', () => { - const actual = _shouldUseOtelHttpInstrumentation({}, {}); - expect(actual).toBe(true); - }); - }); -}); diff --git a/packages/react/src/error.ts b/packages/react/src/error.ts index c10cebe4ecf4..ce6d7a9cd2d5 100644 --- a/packages/react/src/error.ts +++ b/packages/react/src/error.ts @@ -1,5 +1,5 @@ import { captureException, withScope } from '@sentry/browser'; -import { isError } from '@sentry/core'; +import { isError } from '@sentry/core/browser'; import type { ErrorInfo } from 'react'; import { version } from 'react'; diff --git a/packages/react/src/reactrouter-compat-utils/route-manifest.ts b/packages/react/src/reactrouter-compat-utils/route-manifest.ts index bdc49f76705e..3f8c83a27c94 100644 --- a/packages/react/src/reactrouter-compat-utils/route-manifest.ts +++ b/packages/react/src/reactrouter-compat-utils/route-manifest.ts @@ -1,4 +1,4 @@ -import { debug } from '@sentry/core'; +import { debug } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; /** diff --git a/packages/react/src/reactrouter-compat-utils/utils.ts b/packages/react/src/reactrouter-compat-utils/utils.ts index 11a6d3609eaa..a43288823070 100644 --- a/packages/react/src/reactrouter-compat-utils/utils.ts +++ b/packages/react/src/reactrouter-compat-utils/utils.ts @@ -1,5 +1,5 @@ -import type { Span, TransactionSource } from '@sentry/core'; -import { debug, getActiveSpan, getRootSpan, spanToJSON } from '@sentry/core'; +import type { Span, TransactionSource } from '@sentry/core/browser'; +import { debug, getActiveSpan, getRootSpan, spanToJSON } from '@sentry/core/browser'; import { DEBUG_BUILD } from '../debug-build'; import type { Location, MatchRoutes, RouteMatch, RouteObject } from '../types'; import { matchRouteManifest, stripBasenameFromPathname } from './route-manifest'; diff --git a/packages/react/src/reactrouterv3.ts b/packages/react/src/reactrouterv3.ts index f49948a2a74b..cdf97c02d03b 100644 --- a/packages/react/src/reactrouterv3.ts +++ b/packages/react/src/reactrouterv3.ts @@ -4,12 +4,12 @@ import { startBrowserTracingPageLoadSpan, WINDOW, } from '@sentry/browser'; -import type { Integration, TransactionSource } from '@sentry/core'; +import type { Integration, TransactionSource } from '@sentry/core/browser'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { Location } from './types'; // Many of the types below had to be mocked out to prevent typescript issues diff --git a/packages/react/src/redux.ts b/packages/react/src/redux.ts index e9c5eac8424e..8472a590ab56 100644 --- a/packages/react/src/redux.ts +++ b/packages/react/src/redux.ts @@ -1,6 +1,12 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import type { Scope } from '@sentry/core'; -import { addBreadcrumb, addNonEnumerableProperty, getClient, getCurrentScope, getGlobalScope } from '@sentry/core'; +import type { Scope } from '@sentry/core/browser'; +import { + addBreadcrumb, + addNonEnumerableProperty, + getClient, + getCurrentScope, + getGlobalScope, +} from '@sentry/core/browser'; interface Action { type: T; diff --git a/packages/react/src/sdk.ts b/packages/react/src/sdk.ts index 844bc30f1785..03981effc147 100644 --- a/packages/react/src/sdk.ts +++ b/packages/react/src/sdk.ts @@ -1,7 +1,7 @@ import type { BrowserOptions } from '@sentry/browser'; import { init as browserInit, setContext } from '@sentry/browser'; -import type { Client } from '@sentry/core'; -import { applySdkMetadata } from '@sentry/core'; +import type { Client } from '@sentry/core/browser'; +import { applySdkMetadata } from '@sentry/core/browser'; import { version } from 'react'; /** diff --git a/packages/react/src/tanstackrouter.ts b/packages/react/src/tanstackrouter.ts index d2424697d9d5..54b24b3d8490 100644 --- a/packages/react/src/tanstackrouter.ts +++ b/packages/react/src/tanstackrouter.ts @@ -4,12 +4,12 @@ import { startBrowserTracingPageLoadSpan, WINDOW, } from '@sentry/browser'; -import type { Integration } from '@sentry/core'; +import type { Integration } from '@sentry/core/browser'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, -} from '@sentry/core'; +} from '@sentry/core/browser'; import type { VendoredTanstackRouter, VendoredTanstackRouterRouteMatch } from './vendor/tanstackrouter-types'; /** diff --git a/packages/react/test/profiler.test.tsx b/packages/react/test/profiler.test.tsx index 1e88479ffffe..5150975212ee 100644 --- a/packages/react/test/profiler.test.tsx +++ b/packages/react/test/profiler.test.tsx @@ -1,8 +1,8 @@ /** * @vitest-environment jsdom */ -import type { StartSpanOptions } from '@sentry/core'; -import { SentrySpan } from '@sentry/core'; +import type { StartSpanOptions } from '@sentry/core/browser'; +import { SentrySpan } from '@sentry/core/browser'; import { render } from '@testing-library/react'; import { renderHook } from '@testing-library/react-hooks'; import * as React from 'react'; diff --git a/packages/react/test/reactrouter-cross-usage.test.tsx b/packages/react/test/reactrouter-cross-usage.test.tsx index 424821a9ad98..e1225574a5cb 100644 --- a/packages/react/test/reactrouter-cross-usage.test.tsx +++ b/packages/react/test/reactrouter-cross-usage.test.tsx @@ -63,7 +63,7 @@ vi.mock('@sentry/browser', async requireActual => { }; }); -vi.mock('@sentry/core', async requireActual => { +async function coreMock(requireActual: () => Promise) { const actual = (await requireActual()) as any; return { ...actual, @@ -81,7 +81,10 @@ vi.mock('@sentry/core', async requireActual => { return span; }, }; -}); +} + +vi.mock('@sentry/core', coreMock); +vi.mock('@sentry/core/browser', coreMock); describe('React Router cross usage of wrappers', () => { function createMockBrowserClient(): BrowserClient { diff --git a/packages/react/test/reactrouter-descendant-routes.test.tsx b/packages/react/test/reactrouter-descendant-routes.test.tsx index a08893694a30..1172ee8d5d3e 100644 --- a/packages/react/test/reactrouter-descendant-routes.test.tsx +++ b/packages/react/test/reactrouter-descendant-routes.test.tsx @@ -58,14 +58,17 @@ vi.mock('@sentry/browser', async requireActual => { }; }); -vi.mock('@sentry/core', async requireActual => { +async function coreMock(requireActual: () => Promise) { return { ...(await requireActual()), getRootSpan: () => { return mockRootSpan; }, }; -}); +} + +vi.mock('@sentry/core', coreMock); +vi.mock('@sentry/core/browser', coreMock); describe('React Router Descendant Routes', () => { function createMockBrowserClient(): BrowserClient { diff --git a/packages/react/test/reactrouterv6.test.tsx b/packages/react/test/reactrouterv6.test.tsx index fda5043d2e6a..d439e76697d7 100644 --- a/packages/react/test/reactrouterv6.test.tsx +++ b/packages/react/test/reactrouterv6.test.tsx @@ -62,14 +62,17 @@ vi.mock('@sentry/browser', async requireActual => { }; }); -vi.mock('@sentry/core', async requireActual => { +async function coreMock(requireActual: () => Promise) { return { ...(await requireActual()), getRootSpan: () => { return mockRootSpan; }, }; -}); +} + +vi.mock('@sentry/core', coreMock); +vi.mock('@sentry/core/browser', coreMock); describe('reactRouterV6BrowserTracingIntegration', () => { function createMockBrowserClient(): BrowserClient { diff --git a/packages/react/test/redux.test.ts b/packages/react/test/redux.test.ts index 60411418ca6a..09bcfd6ec9c2 100644 --- a/packages/react/test/redux.test.ts +++ b/packages/react/test/redux.test.ts @@ -1,5 +1,5 @@ import * as Sentry from '@sentry/browser'; -import * as SentryCore from '@sentry/core'; +import * as SentryCore from '@sentry/core/browser'; import * as Redux from 'redux'; import type { Mock } from 'vitest'; import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; @@ -8,7 +8,7 @@ import { createReduxEnhancer } from '../src/redux'; const mockSetContext = vi.fn(); const mockGlobalScopeAddEventProcessor = vi.fn(); -vi.mock('@sentry/core', async requireActual => ({ +vi.mock('@sentry/core/browser', async requireActual => ({ ...(await requireActual()), getCurrentScope() { return { diff --git a/packages/react/tsconfig.json b/packages/react/tsconfig.json index 41ff3c42258e..1b28c0b04eb9 100644 --- a/packages/react/tsconfig.json +++ b/packages/react/tsconfig.json @@ -5,6 +5,8 @@ "compilerOptions": { "lib": ["DOM", "es2020"], + "module": "esnext", + "moduleResolution": "bundler", // package-specific options "esModuleInterop": true, "jsx": "react" diff --git a/packages/remix/tsconfig.json b/packages/remix/tsconfig.json index f1f9d9ccc513..a1752fde9b92 100644 --- a/packages/remix/tsconfig.json +++ b/packages/remix/tsconfig.json @@ -5,6 +5,7 @@ "compilerOptions": { "jsx": "react", - "module": "es2020" + "module": "esnext", + "moduleResolution": "bundler" } } diff --git a/packages/solidstart/test/server/errorboundary.test.tsx b/packages/solidstart/test/server/errorboundary.test.tsx index 3ed39bbfea13..5c5a81283644 100644 --- a/packages/solidstart/test/server/errorboundary.test.tsx +++ b/packages/solidstart/test/server/errorboundary.test.tsx @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/unbound-method */ -import type * as SentryCore from '@sentry/core'; +import type * as SentryCore from '@sentry/core/browser'; import { createTransport, getCurrentScope, setCurrentClient } from '@sentry/core'; import { render } from '@solidjs/testing-library'; import userEvent from '@testing-library/user-event'; @@ -8,8 +8,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { NodeClient, withSentryErrorBoundary } from '../../src/server'; const mockCaptureException = vi.fn(); -vi.mock('@sentry/core', async () => { - const actual = await vi.importActual('@sentry/core'); +vi.mock('@sentry/core/browser', async () => { + const actual = await vi.importActual('@sentry/core/browser'); return { ...actual, captureException: (...args) => mockCaptureException(...args), diff --git a/packages/solidstart/tsconfig.json b/packages/solidstart/tsconfig.json index b0eb9ecb6476..78a97ddc222b 100644 --- a/packages/solidstart/tsconfig.json +++ b/packages/solidstart/tsconfig.json @@ -3,5 +3,8 @@ "include": ["src/**/*"], - "compilerOptions": {} + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler" + } } diff --git a/packages/sveltekit/src/server-common/handle.ts b/packages/sveltekit/src/server-common/handle.ts index 26872a0f6f24..c0e33c49c031 100644 --- a/packages/sveltekit/src/server-common/handle.ts +++ b/packages/sveltekit/src/server-common/handle.ts @@ -128,7 +128,6 @@ async function instrumentHandle( // to avoid doing the dynamic import on every request if (options.injectFetchProxyScript == null) { try { - // @ts-expect-error - the dynamic import is fine here const { VERSION } = await import('@sveltejs/kit'); options.injectFetchProxyScript = isFetchProxyRequired(VERSION); } catch { diff --git a/packages/sveltekit/src/vite/svelteConfig.ts b/packages/sveltekit/src/vite/svelteConfig.ts index ae0a29a25243..b8f439092bee 100644 --- a/packages/sveltekit/src/vite/svelteConfig.ts +++ b/packages/sveltekit/src/vite/svelteConfig.ts @@ -39,7 +39,6 @@ export async function loadSvelteConfig(): Promise