diff --git a/.github/ISSUE_TEMPLATE/flaky.yml b/.github/ISSUE_TEMPLATE/flaky.yml index a679cf98d328..2e86f8ebd869 100644 --- a/.github/ISSUE_TEMPLATE/flaky.yml +++ b/.github/ISSUE_TEMPLATE/flaky.yml @@ -19,7 +19,7 @@ body: id: job-name attributes: label: Name of Job - placeholder: "CI: Build & Test / Nextjs (Node 14) Tests" + placeholder: "CI: Build & Test / Nextjs (Node 18) Tests" description: name of job as reported in the status report validations: required: true diff --git a/.github/actions/restore-cache/action.yml b/.github/actions/restore-cache/action.yml index 6cd63a6550e4..e523cca6d904 100644 --- a/.github/actions/restore-cache/action.yml +++ b/.github/actions/restore-cache/action.yml @@ -5,9 +5,6 @@ inputs: dependency_cache_key: description: "The dependency cache key" required: true - node_version: - description: "If set, temporarily set node version to default one before installing, then revert to this version after." - required: false runs: using: "composite" @@ -24,19 +21,7 @@ runs: with: name: build-output - - name: Use default node version for install - if: inputs.node_version && steps.dep-cache.outputs.cache-hit != 'true' - uses: actions/setup-node@v4 - with: - node-version-file: 'package.json' - - name: Install dependencies if: steps.dep-cache.outputs.cache-hit != 'true' run: yarn install --ignore-engines --frozen-lockfile shell: bash - - - name: Revert node version to ${{ inputs.node_version }} - if: inputs.node_version && steps.dep-cache.outputs.cache-hit != 'true' - uses: actions/setup-node@v4 - with: - node-version: ${{ inputs.node_version }} diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 31f5cea28bda..6dc65ca48a99 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -459,7 +459,7 @@ jobs: strategy: fail-fast: false matrix: - node: [14, 16, 18, 20, 22] + node: [18, 20, 22] steps: - name: Check out base commit (${{ github.event.pull_request.base.sha }}) uses: actions/checkout@v4 @@ -478,7 +478,6 @@ jobs: uses: ./.github/actions/restore-cache with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - node_version: ${{ matrix.node == 14 && '14' || '' }} - name: Run affected tests run: yarn test:pr:node --base=${{ github.event.pull_request.base.sha }} @@ -715,7 +714,7 @@ jobs: strategy: fail-fast: false matrix: - node: [14, 16, 18, 20, 22] + node: [18, 20, 22] typescript: - false include: @@ -735,17 +734,13 @@ jobs: uses: ./.github/actions/restore-cache with: dependency_cache_key: ${{ needs.job_build.outputs.dependency_cache_key }} - node_version: ${{ matrix.node == 14 && '14' || '' }} - name: Overwrite typescript version - if: matrix.typescript - run: node ./scripts/use-ts-version.js ${{ matrix.typescript }} + if: matrix.typescript == '3.8' + run: node ./scripts/use-ts-3_8.js working-directory: dev-packages/node-integration-tests - name: Run integration tests - env: - NODE_VERSION: ${{ matrix.node }} - TS_VERSION: ${{ matrix.typescript }} working-directory: dev-packages/node-integration-tests run: yarn test @@ -760,10 +755,6 @@ jobs: matrix: node: [18, 20, 22] remix: [1, 2] - # Remix v2 only supports Node 18+, so run 16 tests separately - include: - - node: 16 - remix: 1 steps: - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) uses: actions/checkout@v4 @@ -1243,7 +1234,7 @@ jobs: echo "One of the dependent jobs have failed. You may need to re-run it." && exit 1 job_compile_bindings_profiling_node: - name: Compile & Test Profiling Bindings (v${{ matrix.node }}) ${{ matrix.target_platform || matrix.os }}, ${{ matrix.node || matrix.container }}, ${{ matrix.arch || matrix.container }}, ${{ contains(matrix.container, 'alpine') && 'musl' || 'glibc' }} + name: Compile profiling-node (v${{ matrix.node }}) ${{ matrix.target_platform || matrix.os }}, ${{ matrix.arch || matrix.container }}, ${{ contains(matrix.container, 'alpine') && 'musl' || 'glibc' }} needs: [job_get_metadata, job_build] # Compiling bindings can be very slow (especially on windows), so only run precompile # Skip precompile unless we are on a release branch as precompile slows down CI times. @@ -1251,16 +1242,14 @@ jobs: (needs.job_get_metadata.outputs.changed_profiling_node == 'true') || (needs.job_get_metadata.outputs.is_release == 'true') runs-on: ${{ matrix.os }} - container: ${{ matrix.container }} + container: + image: ${{ matrix.container }} timeout-minutes: 30 strategy: fail-fast: false matrix: include: # x64 glibc - - os: ubuntu-20.04 - node: 16 - binary: linux-x64-glibc-93 - os: ubuntu-20.04 node: 18 binary: linux-x64-glibc-108 @@ -1272,10 +1261,6 @@ jobs: binary: linux-x64-glibc-127 # x64 musl - - os: ubuntu-20.04 - container: node:16-alpine3.16 - binary: linux-x64-musl-93 - node: 16 - os: ubuntu-20.04 container: node:18-alpine3.17 node: 18 @@ -1290,10 +1275,6 @@ jobs: binary: linux-x64-musl-127 # arm64 glibc - - os: ubuntu-20.04 - arch: arm64 - node: 16 - binary: linux-arm64-glibc-93 - os: ubuntu-20.04 arch: arm64 node: 18 @@ -1308,11 +1289,6 @@ jobs: binary: linux-arm64-glibc-127 # arm64 musl - - os: ubuntu-20.04 - container: node:16-alpine3.16 - arch: arm64 - node: 16 - binary: linux-arm64-musl-93 - os: ubuntu-20.04 arch: arm64 container: node:18-alpine3.17 @@ -1330,10 +1306,6 @@ jobs: binary: linux-arm64-musl-127 # macos x64 - - os: macos-13 - node: 16 - arch: x64 - binary: darwin-x64-93 - os: macos-13 node: 18 arch: x64 @@ -1348,11 +1320,6 @@ jobs: binary: darwin-x64-127 # macos arm64 - - os: macos-13 - arch: arm64 - node: 16 - target_platform: darwin - binary: darwin-arm64-93 - os: macos-13 arch: arm64 node: 18 @@ -1370,10 +1337,6 @@ jobs: binary: darwin-arm64-127 # windows x64 - - os: windows-2022 - node: 16 - arch: x64 - binary: win32-x64-93 - os: windows-2022 node: 18 arch: x64 @@ -1399,8 +1362,13 @@ jobs: with: ref: ${{ env.HEAD_COMMIT }} + # Note: On alpine images, this does nothing + # The node version will be the one that is installed in the image + # If you want to change the node version, you need to change the image + # For non-alpine imgages, this will install the correct version of node - name: Setup Node uses: actions/setup-node@v4 + if: contains(matrix.container, 'alpine') == false with: node-version: ${{ matrix.node }} @@ -1417,10 +1385,10 @@ jobs: run: yarn config set network-timeout 600000 -g - name: Install dependencies - env: - SKIP_PLAYWRIGHT_BROWSER_INSTALL: "1" if: steps.restore-dependencies.outputs.cache-hit != 'true' run: yarn install --ignore-engines --frozen-lockfile + env: + SKIP_PLAYWRIGHT_BROWSER_INSTALL: "1" - name: Configure safe directory run: | @@ -1498,8 +1466,7 @@ jobs: BUILD_ARCH=arm64 \ yarn build:bindings:arm64 - - name: Build Monorepo - if: steps.restore-build.outputs.cache-hit != 'true' + - name: Build profiling-node & its dependencies run: yarn build --scope @sentry/profiling-node - name: Test Bindings diff --git a/CHANGELOG.md b/CHANGELOG.md index e4c8b093cc09..210e2c13ea4b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,7 +10,7 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott -Work in this release was contributed by @maximepvrt and @aloisklink. Thank you for your contributions! +Work in this release was contributed by @aloisklink, @arturovt, @benjick and @maximepvrt. Thank you for your contributions! ## 8.45.0 diff --git a/README.md b/README.md index db7000a9d51f..ed4fc189f11b 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ package. Please refer to the README and instructions of those SDKs for more deta The current version of the SDK is 8.x. Version 7.x of the SDK will continue to receive critical bugfixes until end of 2024. +All SDKs require Node v18+ to run. ESM-only SDKs require Node v18.19.1+ to run. + ## Installation and Usage To install a SDK, simply add the high-level package, for example: diff --git a/dev-packages/browser-integration-tests/package.json b/dev-packages/browser-integration-tests/package.json index 31a7ce76727e..eced2725a93b 100644 --- a/dev-packages/browser-integration-tests/package.json +++ b/dev-packages/browser-integration-tests/package.json @@ -4,12 +4,12 @@ "main": "index.js", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "private": true, "scripts": { "clean": "rimraf -g suites/**/dist loader-suites/**/dist tmp", - "install-browsers": "[[ -z \"$SKIP_PLAYWRIGHT_BROWSER_INSTALL\" ]] && yarn npx playwright install --with-deps || echo 'Skipping browser installation'", + "install-browsers": "[[ -z \"$SKIP_PLAYWRIGHT_BROWSER_INSTALL\" ]] && npx playwright install --with-deps || echo 'Skipping browser installation'", "lint": "eslint . --format stylish", "fix": "eslint . --format stylish --fix", "type-check": "tsc", @@ -52,7 +52,7 @@ }, "devDependencies": { "@types/glob": "8.0.0", - "@types/node": "^14.18.0", + "@types/node": "^18.19.1", "@types/pako": "^2.0.0", "glob": "8.0.3" }, diff --git a/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/init.js b/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/init.js deleted file mode 100644 index 878444f52a0a..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/init.js +++ /dev/null @@ -1,34 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', -}); - -Sentry.metrics.increment('increment'); -Sentry.metrics.increment('increment', 2); -Sentry.metrics.increment('increment', '3'); -Sentry.metrics.distribution('distribution', 42); -Sentry.metrics.distribution('distribution', '45'); -Sentry.metrics.gauge('gauge', 5); -Sentry.metrics.gauge('gauge', '15'); -Sentry.metrics.set('set', 'nope'); -Sentry.metrics.set('set', 'another'); - -Sentry.metrics.timing('timing', 99, 'hour'); -Sentry.metrics.timing('timingSync', () => { - sleepSync(200); -}); -Sentry.metrics.timing('timingAsync', async () => { - await new Promise(resolve => setTimeout(resolve, 200)); -}); - -function sleepSync(milliseconds) { - var start = new Date().getTime(); - for (var i = 0; i < 1e7; i++) { - if (new Date().getTime() - start > milliseconds) { - break; - } - } -} diff --git a/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/test.ts b/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/test.ts deleted file mode 100644 index 38b0139edad3..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/metricsEvent/test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { - getFirstSentryEnvelopeRequest, - properEnvelopeRequestParser, - shouldSkipMetricsTest, -} from '../../../utils/helpers'; - -sentryTest('collects metrics', async ({ getLocalTestUrl, page }) => { - if (shouldSkipMetricsTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestUrl({ testDir: __dirname }); - - const statsdBuffer = await getFirstSentryEnvelopeRequest(page, url, properEnvelopeRequestParser); - const statsdString = new TextDecoder().decode(statsdBuffer); - // Replace all the Txxxxxx to remove the timestamps - const normalisedStatsdString = statsdString.replace(/T\d+\n?/g, 'T000000').trim(); - - const parts = normalisedStatsdString.split('T000000'); - - expect(parts).toEqual([ - 'increment@none:6|c|', - 'distribution@none:42:45|d|', - 'gauge@none:15:5:15:20:2|g|', - 'set@none:3387254:3443787523|s|', - 'timing@hour:99|d|', - expect.stringMatching(/timingSync@second:0.(\d+)\|d\|/), - expect.stringMatching(/timingAsync@second:0.(\d+)\|d\|/), - '', // trailing element - ]); -}); diff --git a/dev-packages/browser-integration-tests/suites/metrics/metricsShim/init.js b/dev-packages/browser-integration-tests/suites/metrics/metricsShim/init.js deleted file mode 100644 index 93c639cbdff9..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/metricsShim/init.js +++ /dev/null @@ -1,13 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', -}); - -// This should not fail -Sentry.metrics.increment('increment'); -Sentry.metrics.distribution('distribution', 42); -Sentry.metrics.gauge('gauge', 5); -Sentry.metrics.set('set', 'nope'); diff --git a/dev-packages/browser-integration-tests/suites/metrics/metricsShim/test.ts b/dev-packages/browser-integration-tests/suites/metrics/metricsShim/test.ts deleted file mode 100644 index e8d0dbcfb274..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/metricsShim/test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { shouldSkipMetricsTest } from '../../../utils/helpers'; - -sentryTest('exports shim metrics integration for non-tracing bundles', async ({ getLocalTestUrl, page }) => { - // Skip in tracing tests - if (!shouldSkipMetricsTest()) { - sentryTest.skip(); - } - - const consoleMessages: string[] = []; - page.on('console', msg => consoleMessages.push(msg.text())); - - let requestCount = 0; - await page.route('https://dsn.ingest.sentry.io/**/*', route => { - requestCount++; - return route.fulfill({ - status: 200, - contentType: 'application/json', - body: JSON.stringify({ id: 'test-id' }), - }); - }); - - const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); - - await page.goto(url); - - expect(requestCount).toBe(0); - expect(consoleMessages).toEqual([ - 'You are using metrics even though this bundle does not include tracing.', - 'You are using metrics even though this bundle does not include tracing.', - 'You are using metrics even though this bundle does not include tracing.', - 'You are using metrics even though this bundle does not include tracing.', - ]); -}); diff --git a/dev-packages/browser-integration-tests/suites/metrics/timing/init.js b/dev-packages/browser-integration-tests/suites/metrics/timing/init.js deleted file mode 100644 index 87f087b04ecf..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/timing/init.js +++ /dev/null @@ -1,39 +0,0 @@ -import * as Sentry from '@sentry/browser'; - -window.Sentry = Sentry; - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - tracesSampleRate: 1.0, - release: '1.0.0', - autoSessionTracking: false, -}); - -window.timingSync = () => { - // Ensure we always have a wrapping span - return Sentry.startSpan({ name: 'manual span' }, () => { - return Sentry.metrics.timing('timingSync', () => { - sleepSync(200); - return 'sync done'; - }); - }); -}; - -window.timingAsync = () => { - // Ensure we always have a wrapping span - return Sentry.startSpan({ name: 'manual span' }, () => { - return Sentry.metrics.timing('timingAsync', async () => { - await new Promise(resolve => setTimeout(resolve, 200)); - return 'async done'; - }); - }); -}; - -function sleepSync(milliseconds) { - var start = new Date().getTime(); - for (var i = 0; i < 1e7; i++) { - if (new Date().getTime() - start > milliseconds) { - break; - } - } -} diff --git a/dev-packages/browser-integration-tests/suites/metrics/timing/test.ts b/dev-packages/browser-integration-tests/suites/metrics/timing/test.ts deleted file mode 100644 index 215f042dcdf7..000000000000 --- a/dev-packages/browser-integration-tests/suites/metrics/timing/test.ts +++ /dev/null @@ -1,159 +0,0 @@ -import { expect } from '@playwright/test'; - -import { sentryTest } from '../../../utils/fixtures'; -import { - envelopeRequestParser, - properEnvelopeRequestParser, - shouldSkipTracingTest, - waitForTransactionRequest, -} from '../../../utils/helpers'; - -sentryTest('allows to wrap sync methods with a timing metric', async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestUrl({ testDir: __dirname }); - - const beforeTime = Math.floor(Date.now() / 1000); - - const metricsPromiseReq = page.waitForRequest(req => { - const postData = req.postData(); - if (!postData) { - return false; - } - - try { - // this implies this is a metrics envelope - return typeof envelopeRequestParser(req) === 'string'; - } catch { - return false; - } - }); - - const transactionPromise = waitForTransactionRequest(page); - - await page.goto(url); - await page.waitForFunction('typeof window.timingSync === "function"'); - const response = await page.evaluate('window.timingSync()'); - - expect(response).toBe('sync done'); - - const statsdString = envelopeRequestParser(await metricsPromiseReq); - const transactionEvent = properEnvelopeRequestParser(await transactionPromise); - - expect(typeof statsdString).toEqual('string'); - - const parsedStatsd = /timingSync@second:(0\.\d+)\|d\|#(.+)\|T(\d+)/.exec(statsdString); - - expect(parsedStatsd).toBeTruthy(); - - const duration = parseFloat(parsedStatsd![1]); - const tags = parsedStatsd![2]; - const timestamp = parseInt(parsedStatsd![3], 10); - - expect(timestamp).toBeGreaterThanOrEqual(beforeTime); - expect(tags).toEqual('release:1.0.0,transaction:manual span'); - expect(duration).toBeGreaterThan(0.2); - expect(duration).toBeLessThan(1); - - expect(transactionEvent).toBeDefined(); - expect(transactionEvent.transaction).toEqual('manual span'); - - const spans = transactionEvent.spans || []; - - expect(spans.length).toBe(1); - const span = spans[0]; - expect(span.op).toEqual('metrics.timing'); - expect(span.description).toEqual('timingSync'); - expect(span.timestamp! - span.start_timestamp).toEqual(duration); - expect(span._metrics_summary).toEqual({ - 'd:timingSync@second': [ - { - count: 1, - max: duration, - min: duration, - sum: duration, - tags: { - release: '1.0.0', - transaction: 'manual span', - }, - }, - ], - }); -}); - -sentryTest('allows to wrap async methods with a timing metric', async ({ getLocalTestUrl, page }) => { - if (shouldSkipTracingTest()) { - sentryTest.skip(); - } - - const url = await getLocalTestUrl({ testDir: __dirname }); - - const beforeTime = Math.floor(Date.now() / 1000); - - const metricsPromiseReq = page.waitForRequest(req => { - const postData = req.postData(); - if (!postData) { - return false; - } - - try { - // this implies this is a metrics envelope - return typeof envelopeRequestParser(req) === 'string'; - } catch { - return false; - } - }); - - const transactionPromise = waitForTransactionRequest(page); - - await page.goto(url); - await page.waitForFunction('typeof window.timingAsync === "function"'); - const response = await page.evaluate('window.timingAsync()'); - - expect(response).toBe('async done'); - - const statsdString = envelopeRequestParser(await metricsPromiseReq); - const transactionEvent = properEnvelopeRequestParser(await transactionPromise); - - expect(typeof statsdString).toEqual('string'); - - const parsedStatsd = /timingAsync@second:(0\.\d+)\|d\|#(.+)\|T(\d+)/.exec(statsdString); - - expect(parsedStatsd).toBeTruthy(); - - const duration = parseFloat(parsedStatsd![1]); - const tags = parsedStatsd![2]; - const timestamp = parseInt(parsedStatsd![3], 10); - - expect(timestamp).toBeGreaterThanOrEqual(beforeTime); - expect(tags).toEqual('release:1.0.0,transaction:manual span'); - expect(duration).toBeGreaterThan(0.2); - expect(duration).toBeLessThan(1); - - expect(transactionEvent).toBeDefined(); - expect(transactionEvent.transaction).toEqual('manual span'); - - const spans = transactionEvent.spans || []; - - expect(spans.length).toBe(1); - const span = spans[0]; - expect(span.op).toEqual('metrics.timing'); - expect(span.description).toEqual('timingAsync'); - expect(span.timestamp! - span.start_timestamp).toEqual(duration); - expect(span._metrics_summary).toEqual({ - 'd:timingAsync@second': [ - { - count: 1, - max: duration, - min: duration, - sum: duration, - tags: { - release: '1.0.0', - transaction: 'manual span', - }, - }, - ], - }); -}); diff --git a/dev-packages/browser-integration-tests/utils/helpers.ts b/dev-packages/browser-integration-tests/utils/helpers.ts index 03c654c22eb1..e02365302331 100644 --- a/dev-packages/browser-integration-tests/utils/helpers.ts +++ b/dev-packages/browser-integration-tests/utils/helpers.ts @@ -270,18 +270,6 @@ export function shouldSkipFeedbackTest(): boolean { return false; } -/** - * We can only test metrics tests in certain bundles/packages: - * - NPM (ESM, CJS) - * - CDN bundles that include tracing - * - * @returns `true` if we should skip the metrics test - */ -export function shouldSkipMetricsTest(): boolean { - const bundle = process.env.PW_BUNDLE as string | undefined; - return bundle != null && !bundle.includes('tracing') && !bundle.includes('esm') && !bundle.includes('cjs'); -} - /** * We only test feature flags integrations in certain bundles/packages: * - NPM (ESM, CJS) diff --git a/dev-packages/e2e-tests/package.json b/dev-packages/e2e-tests/package.json index e1ff6f84550a..958b1645e1c0 100644 --- a/dev-packages/e2e-tests/package.json +++ b/dev-packages/e2e-tests/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@types/glob": "8.0.0", - "@types/node": "^18.0.0", + "@types/node": "^18.19.1", "dotenv": "16.0.3", "esbuild": "0.20.0", "glob": "8.0.3", diff --git a/dev-packages/e2e-tests/test-applications/create-next-app/package.json b/dev-packages/e2e-tests/test-applications/create-next-app/package.json index e91c0ee135e5..fc8f48c822d6 100644 --- a/dev-packages/e2e-tests/test-applications/create-next-app/package.json +++ b/dev-packages/e2e-tests/test-applications/create-next-app/package.json @@ -13,7 +13,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "14.0.0", diff --git a/dev-packages/e2e-tests/test-applications/create-react-app/package.json b/dev-packages/e2e-tests/test-applications/create-react-app/package.json index 916a17260a2a..ee98e1ec3f48 100644 --- a/dev-packages/e2e-tests/test-applications/create-react-app/package.json +++ b/dev-packages/e2e-tests/test-applications/create-react-app/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@sentry/react": "latest || *", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "@types/react": "18.0.0", "@types/react-dom": "18.0.0", "react": "18.2.0", diff --git a/dev-packages/e2e-tests/test-applications/default-browser/package.json b/dev-packages/e2e-tests/test-applications/default-browser/package.json index dc31366f2ea8..635a4bef1955 100644 --- a/dev-packages/e2e-tests/test-applications/default-browser/package.json +++ b/dev-packages/e2e-tests/test-applications/default-browser/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@sentry/browser": "latest || *", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "typescript": "4.9.5" }, "scripts": { diff --git a/dev-packages/e2e-tests/test-applications/ember-classic/package.json b/dev-packages/e2e-tests/test-applications/ember-classic/package.json index 4c887cda10ea..a0c0b4101d09 100644 --- a/dev-packages/e2e-tests/test-applications/ember-classic/package.json +++ b/dev-packages/e2e-tests/test-applications/ember-classic/package.json @@ -48,7 +48,7 @@ "@types/ember__string": "~3.0.15", "@types/ember__template": "~4.0.7", "@types/ember__utils": "~4.0.7", - "@types/node": "18.18.0", + "@types/node": "^18.19.1", "@types/rsvp": "~4.0.9", "broccoli-asset-rev": "~3.0.0", "ember-auto-import": "~2.4.3", @@ -72,7 +72,7 @@ "webpack": "~5.97.0" }, "engines": { - "node": "14.* || 16.* || >= 18" + "node": ">=18" }, "resolutions": { "@babel/traverse": "~7.25.9" diff --git a/dev-packages/e2e-tests/test-applications/ember-embroider/package.json b/dev-packages/e2e-tests/test-applications/ember-embroider/package.json index a8a4db191d81..b96b70876f53 100644 --- a/dev-packages/e2e-tests/test-applications/ember-embroider/package.json +++ b/dev-packages/e2e-tests/test-applications/ember-embroider/package.json @@ -54,14 +54,14 @@ "@sentry/ember": "latest || *", "@sentry-internal/test-utils": "link:../../../test-utils", "@tsconfig/ember": "^3.0.6", - "@types/node": "18.18.0", + "@types/node": "^18.19.1", "@tsconfig/node18": "18.2.4", "@types/rsvp": "^4.0.9", "ts-node": "10.9.1", "typescript": "^5.4.5" }, "engines": { - "node": ">= 18" + "node": ">=18" }, "ember": { "edition": "octane" diff --git a/dev-packages/e2e-tests/test-applications/generic-ts3.8/package.json b/dev-packages/e2e-tests/test-applications/generic-ts3.8/package.json index 77bebc280ea4..c9b564bf1651 100644 --- a/dev-packages/e2e-tests/test-applications/generic-ts3.8/package.json +++ b/dev-packages/e2e-tests/test-applications/generic-ts3.8/package.json @@ -11,7 +11,7 @@ }, "devDependencies": { "typescript": "3.8.3", - "@types/node": "^14.18.0" + "@types/node": "^14.0.0" }, "dependencies": { "@sentry/browser": "latest || *", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-8/package.json b/dev-packages/e2e-tests/test-applications/nestjs-8/package.json index 20724e8d3b78..15ae8cf64bc8 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-8/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-8/package.json @@ -31,7 +31,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json index 62606e825e33..04c1cfc27fb7 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic-with-graphql/package.json @@ -33,7 +33,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json b/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json index 44dcda348383..b51f6e74d3bc 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json @@ -31,7 +31,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json index 6efae6b1c0d5..15392e604a75 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-distributed-tracing/package.json @@ -30,7 +30,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json b/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json index 6da132e74a4c..d456c22370df 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-fastify/package.json @@ -31,7 +31,7 @@ "@nestjs/cli": "^10.0.0", "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json b/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json index 2463d24df940..640889424a87 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-graphql/package.json @@ -33,7 +33,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json index 0b03e38ccbdb..e1dd3d4b3030 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules-decorator/package.json @@ -29,7 +29,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json index 8f90e1582598..78e661aa7d4f 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/package.json @@ -29,7 +29,7 @@ "@nestjs/schematics": "^10.0.0", "@nestjs/testing": "^10.0.0", "@types/express": "^4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "@types/supertest": "^6.0.0", "@typescript-eslint/eslint-plugin": "^6.0.0", "@typescript-eslint/parser": "^6.0.0", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json index de03f89fce27..fa16079822b8 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-13/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-13/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "13.5.7", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json index d1ef013e6ccc..5e42830d0874 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "14.1.3", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-15/package.json b/dev-packages/e2e-tests/test-applications/nextjs-15/package.json index ca92feb9c254..ace02f6a1924 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-15/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-15/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "15.0.0-canary.182", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json index 4b09aff7f937..81f576ef016b 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/package.json @@ -16,7 +16,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "14.0.2", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json b/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json index 304e26d83433..1ebef0ce37ae 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-t3/package.json @@ -32,7 +32,7 @@ "@playwright/test": "^1.44.1", "@sentry-internal/test-utils": "link:../../../test-utils", "@types/eslint": "^8.56.10", - "@types/node": "^20.14.10", + "@types/node": "^18.19.1", "@types/react": "18.3.1", "@types/react-dom": "^18.3.0", "@typescript-eslint/eslint-plugin": "^8.1.0", diff --git a/dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json b/dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json index 10630c257349..9db87a43cd49 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-turbo/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@sentry/nextjs": "latest || *", - "@types/node": "18.11.17", + "@types/node": "^18.19.1", "@types/react": "18.0.26", "@types/react-dom": "18.0.9", "next": "15.0.0", diff --git a/dev-packages/e2e-tests/test-applications/node-connect/package.json b/dev-packages/e2e-tests/test-applications/node-connect/package.json index 276e8654f8f4..ffd692a2175e 100644 --- a/dev-packages/e2e-tests/test-applications/node-connect/package.json +++ b/dev-packages/e2e-tests/test-applications/node-connect/package.json @@ -14,7 +14,7 @@ "@sentry/node": "latest || *", "@sentry/core": "latest || *", "@sentry/opentelemetry": "latest || *", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "connect": "3.7.0", "typescript": "4.9.5", "ts-node": "10.9.1" diff --git a/dev-packages/e2e-tests/test-applications/node-exports-test-app/package.json b/dev-packages/e2e-tests/test-applications/node-exports-test-app/package.json index 5be4d29bbb38..975553194815 100644 --- a/dev-packages/e2e-tests/test-applications/node-exports-test-app/package.json +++ b/dev-packages/e2e-tests/test-applications/node-exports-test-app/package.json @@ -20,7 +20,7 @@ "@sentry/aws-serverless": "latest || *", "@sentry/google-cloud-serverless": "latest || *", "@sentry/bun": "latest || *", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "typescript": "4.9.5" }, "volta": { diff --git a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json index 391514a2c1dd..2931b2bea72f 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-incorrect-instrumentation/package.json @@ -16,7 +16,7 @@ "@trpc/server": "10.45.2", "@trpc/client": "10.45.2", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.20.0", "typescript": "4.9.5", "zod": "~3.22.4" diff --git a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json index 49e98e2c49ad..5e964bbdd8bd 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express-send-to-sentry/package.json @@ -14,7 +14,7 @@ "@sentry/core": "latest || *", "@sentry/node": "latest || *", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.19.2", "typescript": "4.9.5" }, diff --git a/dev-packages/e2e-tests/test-applications/node-express/package.json b/dev-packages/e2e-tests/test-applications/node-express/package.json index bc0b9b4dead7..684a6ae1a3da 100644 --- a/dev-packages/e2e-tests/test-applications/node-express/package.json +++ b/dev-packages/e2e-tests/test-applications/node-express/package.json @@ -16,7 +16,7 @@ "@trpc/server": "10.45.2", "@trpc/client": "10.45.2", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.20.0", "typescript": "4.9.5", "zod": "~3.22.4" diff --git a/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json b/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json index e0a000572a25..f720b711d1fa 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json +++ b/dev-packages/e2e-tests/test-applications/node-fastify-5/package.json @@ -14,7 +14,7 @@ "@sentry/node": "latest || *", "@sentry/core": "latest || *", "@sentry/opentelemetry": "latest || *", - "@types/node": "22.7.5", + "@types/node": "^18.19.1", "fastify": "5.0.0", "typescript": "5.6.3", "ts-node": "10.9.2" diff --git a/dev-packages/e2e-tests/test-applications/node-fastify/package.json b/dev-packages/e2e-tests/test-applications/node-fastify/package.json index b657eddd1de1..1a3847ef3b12 100644 --- a/dev-packages/e2e-tests/test-applications/node-fastify/package.json +++ b/dev-packages/e2e-tests/test-applications/node-fastify/package.json @@ -14,7 +14,7 @@ "@sentry/node": "latest || *", "@sentry/core": "latest || *", "@sentry/opentelemetry": "latest || *", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "fastify": "4.23.2", "typescript": "4.9.5", "ts-node": "10.9.1" diff --git a/dev-packages/e2e-tests/test-applications/node-koa/package.json b/dev-packages/e2e-tests/test-applications/node-koa/package.json index 0f6ed61216db..7962f3153682 100644 --- a/dev-packages/e2e-tests/test-applications/node-koa/package.json +++ b/dev-packages/e2e-tests/test-applications/node-koa/package.json @@ -13,7 +13,7 @@ "@koa/bodyparser": "^5.1.1", "@koa/router": "^12.0.1", "@sentry/node": "latest || *", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "koa": "^2.15.2", "typescript": "4.9.5" }, diff --git a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json index 30cd21643eb8..c5ffdf039553 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-custom-sampler/package.json @@ -16,7 +16,7 @@ "@sentry/node": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.19.2", "typescript": "4.9.5" }, diff --git a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json index fd2b9bf4aafe..88c6f4c3eef9 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-sdk-node/package.json @@ -17,7 +17,7 @@ "@sentry/node": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.19.2", "typescript": "4.9.5" }, diff --git a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json index efe84d86604e..905c94449732 100644 --- a/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json +++ b/dev-packages/e2e-tests/test-applications/node-otel-without-tracing/package.json @@ -20,7 +20,7 @@ "@sentry/node": "latest || *", "@sentry/opentelemetry": "latest || *", "@types/express": "4.17.17", - "@types/node": "18.15.1", + "@types/node": "^18.19.1", "express": "4.19.2", "typescript": "4.9.5" }, diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/pages/client-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/client-error.vue index 5e1a14931f84..ea353639a3f4 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/pages/client-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/pages/client-error.vue @@ -1,11 +1,16 @@ - - + + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts index 4cb23e8b81df..a04ebf73f08d 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/tests/errors.client.test.ts @@ -28,6 +28,47 @@ test.describe('client-side errors', async () => { }); }); + test('captures error thrown in NuxtErrorBoundary', async ({ page }) => { + const errorPromise = waitForError('nuxt-3', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Error thrown in Error Boundary'; + }); + + await page.goto(`/client-error`); + await page.locator('#error-in-error-boundary').click(); + + const error = await errorPromise; + + const expectedBreadcrumb = { + category: 'console', + message: 'Additional functionality in NuxtErrorBoundary', + }; + + const matchingBreadcrumb = error.breadcrumbs.find( + (breadcrumb: { category: string; message: string }) => + breadcrumb.category === expectedBreadcrumb.category && breadcrumb.message === expectedBreadcrumb.message, + ); + + expect(matchingBreadcrumb).toBeTruthy(); + expect(matchingBreadcrumb?.category).toBe(expectedBreadcrumb.category); + expect(matchingBreadcrumb?.message).toBe(expectedBreadcrumb.message); + + expect(error.transaction).toEqual('/client-error'); + expect(error.sdk.name).toEqual('sentry.javascript.nuxt'); + expect(error).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Error thrown in Error Boundary', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + }); + test('shows parametrized route on button error', async ({ page }) => { const errorPromise = waitForError('nuxt-3', async errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Param Route Button'; diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/client-error.vue b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/client-error.vue index c2bdabfb4752..9ec99d1e7471 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/client-error.vue +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/app/pages/client-error.vue @@ -1,11 +1,16 @@ - - + + + + diff --git a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts index c887e255fe57..6694ae851df1 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts +++ b/dev-packages/e2e-tests/test-applications/nuxt-4/tests/errors.client.test.ts @@ -28,6 +28,47 @@ test.describe('client-side errors', async () => { }); }); + test('captures error thrown in NuxtErrorBoundary', async ({ page }) => { + const errorPromise = waitForError('nuxt-4', async errorEvent => { + return errorEvent?.exception?.values?.[0]?.value === 'Error thrown in Error Boundary'; + }); + + await page.goto(`/client-error`); + await page.locator('#error-in-error-boundary').click(); + + const error = await errorPromise; + + const expectedBreadcrumb = { + category: 'console', + message: 'Additional functionality in NuxtErrorBoundary', + }; + + const matchingBreadcrumb = error.breadcrumbs.find( + (breadcrumb: { category: string; message: string }) => + breadcrumb.category === expectedBreadcrumb.category && breadcrumb.message === expectedBreadcrumb.message, + ); + + expect(matchingBreadcrumb).toBeTruthy(); + expect(matchingBreadcrumb?.category).toBe(expectedBreadcrumb.category); + expect(matchingBreadcrumb?.message).toBe(expectedBreadcrumb.message); + + expect(error.transaction).toEqual('/client-error'); + expect(error.sdk.name).toEqual('sentry.javascript.nuxt'); + expect(error).toMatchObject({ + exception: { + values: [ + { + type: 'Error', + value: 'Error thrown in Error Boundary', + mechanism: { + handled: false, + }, + }, + ], + }, + }); + }); + test('shows parametrized route on button error', async ({ page }) => { const errorPromise = waitForError('nuxt-4', async errorEvent => { return errorEvent?.exception?.values?.[0]?.value === 'Error thrown from Param Route Button'; diff --git a/dev-packages/e2e-tests/test-applications/react-19/package.json b/dev-packages/e2e-tests/test-applications/react-19/package.json index 5de946437a44..b5d3d25d5fb7 100644 --- a/dev-packages/e2e-tests/test-applications/react-19/package.json +++ b/dev-packages/e2e-tests/test-applications/react-19/package.json @@ -6,7 +6,7 @@ "@sentry/react": "latest || *", "history": "4.9.0", "@types/history": "4.7.11", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "@types/react": "npm:types-react@rc", "@types/react-dom": "npm:types-react-dom@rc", "react": "19.0.0-rc-935180c7e0-20240524", diff --git a/dev-packages/e2e-tests/test-applications/react-create-hash-router/package.json b/dev-packages/e2e-tests/test-applications/react-create-hash-router/package.json index e475fb505fc8..bfe148db10a6 100644 --- a/dev-packages/e2e-tests/test-applications/react-create-hash-router/package.json +++ b/dev-packages/e2e-tests/test-applications/react-create-hash-router/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@sentry/react": "latest || *", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "@types/react": "18.0.0", "@types/react-dom": "18.0.0", "react": "18.2.0", diff --git a/dev-packages/e2e-tests/test-applications/react-router-5/package.json b/dev-packages/e2e-tests/test-applications/react-router-5/package.json index 0b208b3f5a65..b23643e8be31 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-5/package.json +++ b/dev-packages/e2e-tests/test-applications/react-router-5/package.json @@ -6,7 +6,7 @@ "@sentry/react": "latest || *", "history": "4.9.0", "@types/history": "4.7.11", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "@types/react": "18.0.0", "@types/react-dom": "18.0.0", "@types/react-router": "5.1.20", diff --git a/dev-packages/e2e-tests/test-applications/react-send-to-sentry/package.json b/dev-packages/e2e-tests/test-applications/react-send-to-sentry/package.json index 836707b3017f..9be121c97312 100644 --- a/dev-packages/e2e-tests/test-applications/react-send-to-sentry/package.json +++ b/dev-packages/e2e-tests/test-applications/react-send-to-sentry/package.json @@ -4,7 +4,7 @@ "private": true, "dependencies": { "@sentry/react": "latest || *", - "@types/node": "16.7.13", + "@types/node": "^18.19.1", "@types/react": "18.0.0", "@types/react-dom": "18.0.0", "react": "18.2.0", diff --git a/dev-packages/e2e-tests/test-applications/vue-3/package.json b/dev-packages/e2e-tests/test-applications/vue-3/package.json index f34bdf6d6c0e..06436101eee8 100644 --- a/dev-packages/e2e-tests/test-applications/vue-3/package.json +++ b/dev-packages/e2e-tests/test-applications/vue-3/package.json @@ -25,7 +25,7 @@ "@sentry-internal/test-utils": "link:../../../test-utils", "@sentry/core": "latest || *", "@tsconfig/node20": "^20.1.2", - "@types/node": "^20.11.10", + "@types/node": "^18.19.1", "@vitejs/plugin-vue": "^5.0.3", "@vitejs/plugin-vue-jsx": "^3.1.0", "@vue/tsconfig": "^0.5.1", diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index 24be97583c1c..f27d4c7e750e 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -3,7 +3,7 @@ "version": "8.45.0", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "private": true, "main": "build/cjs/index.js", @@ -16,7 +16,7 @@ "build:types": "tsc -p tsconfig.types.json", "clean": "rimraf -g **/node_modules && run-p clean:script", "clean:script": "node scripts/clean.js", - "prisma:init": "(cd suites/tracing/prisma-orm && ts-node ./setup.ts)", + "prisma:init": "cd suites/tracing/prisma-orm && yarn && yarn setup", "lint": "eslint . --format stylish", "fix": "eslint . --format stylish --fix", "type-check": "tsc", @@ -30,7 +30,7 @@ "@nestjs/common": "10.4.6", "@nestjs/core": "10.4.6", "@nestjs/platform-express": "10.4.6", - "@prisma/client": "5.9.1", + "@prisma/client": "5.22.0", "@sentry/aws-serverless": "8.45.0", "@sentry/core": "8.45.0", "@sentry/node": "8.45.0", diff --git a/dev-packages/node-integration-tests/scripts/use-ts-version.js b/dev-packages/node-integration-tests/scripts/use-ts-3_8.js similarity index 80% rename from dev-packages/node-integration-tests/scripts/use-ts-version.js rename to dev-packages/node-integration-tests/scripts/use-ts-3_8.js index 0b64d735436c..e8b43ecfe6f2 100644 --- a/dev-packages/node-integration-tests/scripts/use-ts-version.js +++ b/dev-packages/node-integration-tests/scripts/use-ts-3_8.js @@ -5,11 +5,14 @@ const { writeFileSync } = require('fs'); const cwd = join(__dirname, '../../..'); -const tsVersion = process.argv[2] || '3.8'; +const tsVersion = '3.8'; -console.log(`Installing typescript@${tsVersion}...`); +console.log(`Installing typescript@${tsVersion}, and @types/node@14...`); -execSync(`yarn add --dev --ignore-workspace-root-check typescript@${tsVersion}`, { stdio: 'inherit', cwd }); +execSync(`yarn add --dev --ignore-workspace-root-check typescript@${tsVersion} @types/node@^14`, { + stdio: 'inherit', + cwd, +}); console.log('Removing unsupported tsconfig options...'); diff --git a/dev-packages/node-integration-tests/suites/anr/test.ts b/dev-packages/node-integration-tests/suites/anr/test.ts index d1d9c684bf60..1366600d5280 100644 --- a/dev-packages/node-integration-tests/suites/anr/test.ts +++ b/dev-packages/node-integration-tests/suites/anr/test.ts @@ -1,5 +1,4 @@ import type { Event } from '@sentry/core'; -import { conditionalTest } from '../../utils'; import { cleanupChildProcesses, createRunner } from '../../utils/runner'; const ANR_EVENT = { @@ -107,7 +106,7 @@ const ANR_EVENT_WITH_DEBUG_META: Event = { }, }; -conditionalTest({ min: 16 })('should report ANR when event loop blocked', () => { +describe('should report ANR when event loop blocked', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/suites/contextLines/test.ts b/dev-packages/node-integration-tests/suites/contextLines/test.ts index 1912f0b57f04..06591bcfbe8e 100644 --- a/dev-packages/node-integration-tests/suites/contextLines/test.ts +++ b/dev-packages/node-integration-tests/suites/contextLines/test.ts @@ -1,8 +1,7 @@ import { join } from 'path'; -import { conditionalTest } from '../../utils'; import { createRunner } from '../../utils/runner'; -conditionalTest({ min: 18 })('ContextLines integration in ESM', () => { +describe('ContextLines integration in ESM', () => { test('reads encoded context lines from filenames with spaces', done => { expect.assertions(1); const instrumentPath = join(__dirname, 'instrument.mjs'); diff --git a/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts index d1584c2ea32d..828ff702f45b 100644 --- a/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts +++ b/dev-packages/node-integration-tests/suites/esm/import-in-the-middle/test.ts @@ -1,13 +1,12 @@ import { spawnSync } from 'child_process'; import { join } from 'path'; -import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses } from '../../../utils/runner'; afterAll(() => { cleanupChildProcesses(); }); -conditionalTest({ min: 18 })('import-in-the-middle', () => { +describe('import-in-the-middle', () => { test('onlyIncludeInstrumentedModules', () => { const result = spawnSync('node', [join(__dirname, 'app.mjs')], { encoding: 'utf-8' }); expect(result.stderr).not.toMatch('should be the only hooked modules but we just hooked'); diff --git a/dev-packages/node-integration-tests/suites/esm/modules-integration/test.ts b/dev-packages/node-integration-tests/suites/esm/modules-integration/test.ts index 556ec1d52a57..eaee003781f3 100644 --- a/dev-packages/node-integration-tests/suites/esm/modules-integration/test.ts +++ b/dev-packages/node-integration-tests/suites/esm/modules-integration/test.ts @@ -1,11 +1,10 @@ -import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; afterAll(() => { cleanupChildProcesses(); }); -conditionalTest({ min: 18 })('modulesIntegration', () => { +describe('modulesIntegration', () => { test('does not crash ESM setups', done => { createRunner(__dirname, 'app.mjs').ensureNoErrorOutput().start(done); }); diff --git a/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js b/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js deleted file mode 100644 index 2621828973ab..000000000000 --- a/dev-packages/node-integration-tests/suites/metrics/should-exit-forced.js +++ /dev/null @@ -1,19 +0,0 @@ -const Sentry = require('@sentry/node'); - -function configureSentry() { - Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - autoSessionTracking: false, - }); - - Sentry.metrics.increment('test'); -} - -async function main() { - configureSentry(); - await new Promise(resolve => setTimeout(resolve, 1000)); - process.exit(0); -} - -main(); diff --git a/dev-packages/node-integration-tests/suites/metrics/should-exit.js b/dev-packages/node-integration-tests/suites/metrics/should-exit.js deleted file mode 100644 index 01a6f0194507..000000000000 --- a/dev-packages/node-integration-tests/suites/metrics/should-exit.js +++ /dev/null @@ -1,18 +0,0 @@ -const Sentry = require('@sentry/node'); - -function configureSentry() { - Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - autoSessionTracking: false, - }); - - Sentry.metrics.increment('test'); -} - -async function main() { - configureSentry(); - await new Promise(resolve => setTimeout(resolve, 1000)); -} - -main(); diff --git a/dev-packages/node-integration-tests/suites/metrics/test.ts b/dev-packages/node-integration-tests/suites/metrics/test.ts deleted file mode 100644 index 2c3cc350eeba..000000000000 --- a/dev-packages/node-integration-tests/suites/metrics/test.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { createRunner } from '../../utils/runner'; - -describe('metrics', () => { - test('should exit', done => { - const runner = createRunner(__dirname, 'should-exit.js').start(); - - setTimeout(() => { - expect(runner.childHasExited()).toBe(true); - done(); - }, 5_000); - }); - - test('should exit forced', done => { - const runner = createRunner(__dirname, 'should-exit-forced.js').start(); - - setTimeout(() => { - expect(runner.childHasExited()).toBe(true); - done(); - }, 5_000); - }); -}); diff --git a/dev-packages/node-integration-tests/suites/no-code/test.ts b/dev-packages/node-integration-tests/suites/no-code/test.ts index dfaae9de7cdc..fdcd5bd25fc6 100644 --- a/dev-packages/node-integration-tests/suites/no-code/test.ts +++ b/dev-packages/node-integration-tests/suites/no-code/test.ts @@ -1,4 +1,3 @@ -import { conditionalTest } from '../../utils'; import { cleanupChildProcesses, createRunner } from '../../utils/runner'; const EVENT = { @@ -25,7 +24,7 @@ describe('no-code init', () => { .start(done); }); - conditionalTest({ min: 18 })('--import', () => { + describe('--import', () => { test('ESM', done => { createRunner(__dirname, 'app.mjs') .withFlags('--import=@sentry/node/init') diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts index 779b341d9f40..7ed9d352474a 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/test.ts @@ -37,7 +37,7 @@ const EXPECTED_LOCAL_VARIABLES_EVENT = { }, }; -conditionalTest({ min: 18 })('LocalVariables integration', () => { +describe('LocalVariables integration', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/ai/test.ts b/dev-packages/node-integration-tests/suites/tracing/ai/test.ts index e269f9da9db3..bc263e9fc610 100644 --- a/dev-packages/node-integration-tests/suites/tracing/ai/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/ai/test.ts @@ -1,8 +1,7 @@ -import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; // `ai` SDK only support Node 18+ -conditionalTest({ min: 18 })('ai', () => { +describe('ai', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js b/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js deleted file mode 100644 index 422fa4c504a5..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/scenario.js +++ /dev/null @@ -1,50 +0,0 @@ -const { loggingTransport } = require('@sentry-internal/node-integration-tests'); -const Sentry = require('@sentry/node'); - -Sentry.init({ - dsn: 'https://public@dsn.ingest.sentry.io/1337', - release: '1.0', - tracesSampleRate: 1.0, - transport: loggingTransport, -}); - -Sentry.startSpan( - { - name: 'Test Transaction', - op: 'transaction', - }, - () => { - Sentry.metrics.increment('root-counter', 1, { - tags: { - email: 'jon.doe@example.com', - }, - }); - Sentry.metrics.increment('root-counter', 1, { - tags: { - email: 'jane.doe@example.com', - }, - }); - - Sentry.startSpan( - { - name: 'Some other span', - op: 'transaction', - }, - () => { - Sentry.metrics.increment('root-counter'); - Sentry.metrics.increment('root-counter'); - Sentry.metrics.increment('root-counter', 2); - - Sentry.metrics.set('root-set', 'some-value'); - Sentry.metrics.set('root-set', 'another-value'); - Sentry.metrics.set('root-set', 'another-value'); - - Sentry.metrics.gauge('root-gauge', 42); - Sentry.metrics.gauge('root-gauge', 20); - - Sentry.metrics.distribution('root-distribution', 42); - Sentry.metrics.distribution('root-distribution', 20); - }, - ); - }, -); diff --git a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/test.ts b/dev-packages/node-integration-tests/suites/tracing/metric-summaries/test.ts deleted file mode 100644 index 94f5fdc30c70..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/metric-summaries/test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { createRunner } from '../../../utils/runner'; - -const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - _metrics_summary: { - 'c:root-counter@none': [ - { - min: 1, - max: 1, - count: 1, - sum: 1, - tags: { - release: '1.0', - transaction: 'Test Transaction', - email: 'jon.doe@example.com', - }, - }, - { - min: 1, - max: 1, - count: 1, - sum: 1, - tags: { - release: '1.0', - transaction: 'Test Transaction', - email: 'jane.doe@example.com', - }, - }, - ], - }, - spans: expect.arrayContaining([ - expect.objectContaining({ - description: 'Some other span', - op: 'transaction', - _metrics_summary: { - 'c:root-counter@none': [ - { - min: 1, - max: 2, - count: 3, - sum: 4, - tags: { - release: '1.0', - transaction: 'Test Transaction', - }, - }, - ], - 's:root-set@none': [ - { - min: 0, - max: 1, - count: 3, - sum: 2, - tags: { - release: '1.0', - transaction: 'Test Transaction', - }, - }, - ], - 'g:root-gauge@none': [ - { - min: 20, - max: 42, - count: 2, - sum: 62, - tags: { - release: '1.0', - transaction: 'Test Transaction', - }, - }, - ], - 'd:root-distribution@none': [ - { - min: 20, - max: 42, - count: 2, - sum: 62, - tags: { - release: '1.0', - transaction: 'Test Transaction', - }, - }, - ], - }, - }), - ]), -}; - -test('Should add metric summaries to spans', done => { - createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done); -}); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/package.json b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/package.json index b40c92b4356e..b8721038c83b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/package.json +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "engines": { - "node": ">=16" + "node": ">=18" }, "scripts": { "db-up": "docker compose up -d", @@ -16,7 +16,7 @@ "author": "", "license": "ISC", "dependencies": { - "@prisma/client": "5.9.1", - "prisma": "^5.9.1" + "@prisma/client": "5.22.0", + "prisma": "5.22.0" } } diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/setup.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/setup.ts deleted file mode 100755 index a0052511b380..000000000000 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/setup.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { execSync } from 'child_process'; -import { parseSemver } from '@sentry/core'; - -const NODE_VERSION = parseSemver(process.versions.node); - -// Prisma v5 requires Node.js v16+ -// https://www.prisma.io/docs/orm/more/upgrade-guides/upgrading-versions/upgrading-to-prisma-5#nodejs-minimum-version-change -if (NODE_VERSION.major && NODE_VERSION.major < 16) { - // eslint-disable-next-line no-console - console.warn(`Skipping Prisma tests on Node: ${NODE_VERSION.major}`); - process.exit(0); -} - -try { - execSync('yarn && yarn setup'); -} catch (_) { - process.exit(1); -} diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts index dd92de5d0292..d5e9f7ba372f 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/test.ts @@ -1,105 +1,138 @@ -import { conditionalTest } from '../../../utils'; import { createRunner } from '../../../utils/runner'; -conditionalTest({ min: 16 })('Prisma ORM Tests', () => { +describe('Prisma ORM Tests', () => { test('CJS - should instrument PostgreSQL queries from Prisma ORM', done => { - const EXPECTED_TRANSACTION = { - transaction: 'Test Transaction', - spans: expect.arrayContaining([ - expect.objectContaining({ - data: { - method: 'create', - model: 'User', - name: 'User.create', - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:operation', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:serialize', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:connect', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:engine', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'db.type': 'postgres', - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:engine:connection', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'db.statement': expect.stringContaining( - 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', - ), - 'sentry.origin': 'auto.db.otel.prisma', - 'db.system': 'prisma', - 'sentry.op': 'db', - }, - description: expect.stringContaining( - 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', - ), - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:engine:serialize', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:engine:response_json_serialization', - status: 'ok', - }), - expect.objectContaining({ - data: { - method: 'findMany', - model: 'User', - name: 'User.findMany', - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:operation', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:client:serialize', - status: 'ok', - }), - expect.objectContaining({ - data: { - 'sentry.origin': 'auto.db.otel.prisma', - }, - description: 'prisma:engine', - status: 'ok', - }), - ]), - }; + createRunner(__dirname, 'scenario.js') + .expect({ + transaction: transaction => { + expect(transaction.transaction).toBe('Test Transaction'); - createRunner(__dirname, 'scenario.js').expect({ transaction: EXPECTED_TRANSACTION }).start(done); + const spans = transaction.spans || []; + expect(spans.length).toBeGreaterThanOrEqual(5); + + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + method: 'create', + model: 'User', + name: 'User.create', + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:operation', + status: 'ok', + }), + ); + + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:serialize', + status: 'ok', + }), + ); + + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:connect', + status: 'ok', + }), + ); + + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:engine', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + 'sentry.op': 'db', + 'db.system': 'postgresql', + }, + description: 'prisma:engine:connection', + status: 'ok', + op: 'db', + }), + ); + + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'db.statement': expect.stringContaining( + 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', + ), + 'sentry.origin': 'auto.db.otel.prisma', + 'sentry.op': 'db', + 'db.system': 'postgresql', + 'otel.kind': 'CLIENT', + }, + description: expect.stringContaining( + 'INSERT INTO "public"."User" ("createdAt","email","name") VALUES ($1,$2,$3) RETURNING "public"."User"."id", "public"."User"."createdAt", "public"."User"."email", "public"."User"."name" /* traceparent', + ), + status: 'ok', + op: 'db', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:engine:serialize', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:engine:response_json_serialization', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + method: 'findMany', + model: 'User', + name: 'User.findMany', + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:operation', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:client:serialize', + status: 'ok', + }), + ); + expect(spans).toContainEqual( + expect.objectContaining({ + data: { + 'sentry.origin': 'auto.db.otel.prisma', + }, + description: 'prisma:engine', + status: 'ok', + }), + ); + }, + }) + .start(done); }); }); diff --git a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/yarn.lock b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/yarn.lock index 9c0fc47be4be..860aa032d6cc 100644 --- a/dev-packages/node-integration-tests/suites/tracing/prisma-orm/yarn.lock +++ b/dev-packages/node-integration-tests/suites/tracing/prisma-orm/yarn.lock @@ -2,50 +2,57 @@ # yarn lockfile v1 -"@prisma/client@5.9.1": - version "5.9.1" - resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.9.1.tgz#d92bd2f7f006e0316cb4fda9d73f235965cf2c64" - integrity sha512-caSOnG4kxcSkhqC/2ShV7rEoWwd3XrftokxJqOCMVvia4NYV/TPtJlS9C2os3Igxw/Qyxumj9GBQzcStzECvtQ== - -"@prisma/debug@5.9.1": - version "5.9.1" - resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.9.1.tgz#906274e73d3267f88b69459199fa3c51cd9511a3" - integrity sha512-yAHFSFCg8KVoL0oRUno3m60GAjsUKYUDkQ+9BA2X2JfVR3kRVSJFc/GpQ2fSORi4pSHZR9orfM4UC9OVXIFFTA== - -"@prisma/engines-version@5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64": - version "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" - resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64.tgz#54d2164f28d23e09d41cf9eb0bddbbe7f3aaa660" - integrity sha512-HFl7275yF0FWbdcNvcSRbbu9JCBSLMcurYwvWc8WGDnpu7APxQo2ONtZrUggU3WxLxUJ2uBX+0GOFIcJeVeOOQ== - -"@prisma/engines@5.9.1": - version "5.9.1" - resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.9.1.tgz#767539afc6f193a182d0495b30b027f61f279073" - integrity sha512-gkdXmjxQ5jktxWNdDA5aZZ6R8rH74JkoKq6LD5mACSvxd2vbqWeWIOV0Py5wFC8vofOYShbt6XUeCIUmrOzOnQ== +"@prisma/client@5.22.0": + version "5.22.0" + resolved "https://registry.yarnpkg.com/@prisma/client/-/client-5.22.0.tgz#da1ca9c133fbefe89e0da781c75e1c59da5f8802" + integrity sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA== + +"@prisma/debug@5.22.0": + version "5.22.0" + resolved "https://registry.yarnpkg.com/@prisma/debug/-/debug-5.22.0.tgz#58af56ed7f6f313df9fb1042b6224d3174bbf412" + integrity sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ== + +"@prisma/engines-version@5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2": + version "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" + resolved "https://registry.yarnpkg.com/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz#d534dd7235c1ba5a23bacd5b92cc0ca3894c28f4" + integrity sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ== + +"@prisma/engines@5.22.0": + version "5.22.0" + resolved "https://registry.yarnpkg.com/@prisma/engines/-/engines-5.22.0.tgz#28f3f52a2812c990a8b66eb93a0987816a5b6d84" + integrity sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA== dependencies: - "@prisma/debug" "5.9.1" - "@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" - "@prisma/fetch-engine" "5.9.1" - "@prisma/get-platform" "5.9.1" - -"@prisma/fetch-engine@5.9.1": - version "5.9.1" - resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.9.1.tgz#5d3b2c9af54a242e37b3f9561b59ab72f8e92818" - integrity sha512-l0goQOMcNVOJs1kAcwqpKq3ylvkD9F04Ioe1oJoCqmz05mw22bNAKKGWuDd3zTUoUZr97va0c/UfLNru+PDmNA== + "@prisma/debug" "5.22.0" + "@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" + "@prisma/fetch-engine" "5.22.0" + "@prisma/get-platform" "5.22.0" + +"@prisma/fetch-engine@5.22.0": + version "5.22.0" + resolved "https://registry.yarnpkg.com/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz#4fb691b483a450c5548aac2f837b267dd50ef52e" + integrity sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA== dependencies: - "@prisma/debug" "5.9.1" - "@prisma/engines-version" "5.9.0-32.23fdc5965b1e05fc54e5f26ed3de66776b93de64" - "@prisma/get-platform" "5.9.1" - -"@prisma/get-platform@5.9.1": - version "5.9.1" - resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.9.1.tgz#a66bb46ab4d30db786c84150ef074ab0aad4549e" - integrity sha512-6OQsNxTyhvG+T2Ksr8FPFpuPeL4r9u0JF0OZHUBI/Uy9SS43sPyAIutt4ZEAyqWQt104ERh70EZedkHZKsnNbg== + "@prisma/debug" "5.22.0" + "@prisma/engines-version" "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2" + "@prisma/get-platform" "5.22.0" + +"@prisma/get-platform@5.22.0": + version "5.22.0" + resolved "https://registry.yarnpkg.com/@prisma/get-platform/-/get-platform-5.22.0.tgz#fc675bc9d12614ca2dade0506c9c4a77e7dddacd" + integrity sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q== dependencies: - "@prisma/debug" "5.9.1" + "@prisma/debug" "5.22.0" -prisma@^5.9.1: - version "5.9.1" - resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.9.1.tgz#baa3dd635fbf71504980978f10f55ea11068f6aa" - integrity sha512-Hy/8KJZz0ELtkw4FnG9MS9rNWlXcJhf98Z2QMqi0QiVMoS8PzsBkpla0/Y5hTlob8F3HeECYphBjqmBxrluUrQ== +fsevents@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +prisma@5.22.0: + version "5.22.0" + resolved "https://registry.yarnpkg.com/prisma/-/prisma-5.22.0.tgz#1f6717ff487cdef5f5799cc1010459920e2e6197" + integrity sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A== dependencies: - "@prisma/engines" "5.9.1" + "@prisma/engines" "5.22.0" + optionalDependencies: + fsevents "2.3.3" diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-breadcrumbs/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-breadcrumbs/test.ts index c0d783aaa594..254d197c85c3 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-breadcrumbs/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-breadcrumbs/test.ts @@ -1,8 +1,7 @@ -import { conditionalTest } from '../../../../utils'; import { createRunner } from '../../../../utils/runner'; import { createTestServer } from '../../../../utils/server'; -conditionalTest({ min: 18 })('outgoing fetch', () => { +describe('outgoing fetch', () => { test('outgoing fetch requests create breadcrumbs', done => { createTestServer(done) .start() diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-no-tracing/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-no-tracing/test.ts index 9c732d899cde..906fa6541dd6 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-no-tracing/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-no-tracing/test.ts @@ -1,8 +1,7 @@ -import { conditionalTest } from '../../../../utils'; import { createRunner } from '../../../../utils/runner'; import { createTestServer } from '../../../../utils/server'; -conditionalTest({ min: 18 })('outgoing fetch', () => { +describe('outgoing fetch', () => { test('outgoing fetch requests are correctly instrumented with tracing disabled', done => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-sampled-no-active-span/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-sampled-no-active-span/test.ts index fde1c787829a..afe60d27b22a 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-sampled-no-active-span/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-sampled-no-active-span/test.ts @@ -1,8 +1,7 @@ -import { conditionalTest } from '../../../../utils'; import { createRunner } from '../../../../utils/runner'; import { createTestServer } from '../../../../utils/server'; -conditionalTest({ min: 18 })('outgoing fetch', () => { +describe('outgoing fetch', () => { test('outgoing sampled fetch requests without active span are correctly instrumented', done => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-unsampled/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-unsampled/test.ts index d288e9a03fbf..cb85ca98ca0b 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/fetch-unsampled/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/fetch-unsampled/test.ts @@ -1,8 +1,7 @@ -import { conditionalTest } from '../../../../utils'; import { createRunner } from '../../../../utils/runner'; import { createTestServer } from '../../../../utils/server'; -conditionalTest({ min: 18 })('outgoing fetch', () => { +describe('outgoing fetch', () => { test('outgoing fetch requests are correctly instrumented when not sampled', done => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-esm/test.ts b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-esm/test.ts index 72f625aedeb7..f3d58877c8f3 100644 --- a/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-esm/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/requests/http-sampled-esm/test.ts @@ -1,9 +1,8 @@ import { join } from 'path'; -import { conditionalTest } from '../../../../utils'; import { createRunner } from '../../../../utils/runner'; import { createTestServer } from '../../../../utils/server'; -conditionalTest({ min: 18 })('outgoing http in ESM', () => { +describe('outgoing http in ESM', () => { test('outgoing sampled http requests are correctly instrumented in ESM', done => { expect.assertions(11); diff --git a/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts b/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts index c4a0ae29fe38..6c5fd17f833a 100644 --- a/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing/tedious/test.ts @@ -1,11 +1,10 @@ -import { conditionalTest } from '../../../utils'; import { cleanupChildProcesses, createRunner } from '../../../utils/runner'; jest.setTimeout(75000); // Tedious version we are testing against only supports Node 18+ // https://github.com/tediousjs/tedious/blob/8310c455a2cc1cba83c1ca3c16677da4f83e12a9/package.json#L38 -conditionalTest({ min: 18 })('tedious auto instrumentation', () => { +describe('tedious auto instrumentation', () => { afterAll(() => { cleanupChildProcesses(); }); diff --git a/dev-packages/rollup-utils/plugins/bundlePlugins.mjs b/dev-packages/rollup-utils/plugins/bundlePlugins.mjs index dce0ca15bf35..9d6edd3157c0 100644 --- a/dev-packages/rollup-utils/plugins/bundlePlugins.mjs +++ b/dev-packages/rollup-utils/plugins/bundlePlugins.mjs @@ -126,8 +126,6 @@ export function makeTerserPlugin() { '_sentryId', // Keeps the frozen DSC on a Sentry Span '_frozenDsc', - // This keeps metrics summary on spans - '_metrics_summary', // These are used to keep span & scope relationships '_sentryRootSpan', '_sentryChildSpans', diff --git a/dev-packages/test-utils/package.json b/dev-packages/test-utils/package.json index 09ad4cf5a55d..8e8afec9f698 100644 --- a/dev-packages/test-utils/package.json +++ b/dev-packages/test-utils/package.json @@ -28,7 +28,7 @@ }, "sideEffects": false, "engines": { - "node": ">=14.18" + "node": ">=18" }, "scripts": { "fix": "eslint . --format stylish --fix", diff --git a/docs/migration/v8-to-v9.md b/docs/migration/v8-to-v9.md index ff1adc85dfd4..0f92cab5bc93 100644 --- a/docs/migration/v8-to-v9.md +++ b/docs/migration/v8-to-v9.md @@ -24,8 +24,8 @@ This includes features like Nullish Coalescing (`??`), Optional Chaining (`?.`), If you observe failures due to syntax or features listed above, it may be an indicator that your current runtime does not support ES2020. If your runtime does not support ES2020, we recommend transpiling the SDK using Babel or similar tooling. -**Node.js:** The minimum supported Node.js versions are TBD, TBD, and TBD. -We no longer test against Node TBD, TBD, or TBD and cannot guarantee that the SDK will work as expected on these versions. +**Node.js:** The minimum supported Node.js version is **18.0.0**, except for ESM-only SDKs (nuxt, solidstart, astro) which require Node **18.19.1** or up. +We no longer test against Node 14 and Node 16 and cannot guarantee that the SDK will work as expected on these versions. **Browsers:** Due to SDK code now including ES2020 features, the minimum supported browser list now looks as follows: @@ -104,10 +104,12 @@ It will be removed in a future major version. ### `@sentry/core` -- The `getNumberOfUrlSegments` method has been removed. There are no replacements. +- The `getNumberOfUrlSegments` method has been removed. There is no replacement. +- The `validSeverityLevels` export has been removed. There is no replacement. ### `@sentry/nestjs` +- Removed `WithSentry` decorator. Use `SentryExceptionCaptured` instead. - Removed `SentryService`. If you are using `@sentry/nestjs` you can safely remove any references to the `SentryService`. If you are using another package migrate to `@sentry/nestjs` and remove the `SentryService` afterwards. @@ -175,6 +177,10 @@ The following outlines deprecations that were introduced in version 8 of the SDK To enable session tracking, it is recommended to unset `autoSessionTracking` and ensure that either, in browser environments the `browserSessionIntegration` is added, or in server environments the `httpIntegration` is added. To disable session tracking, it is recommended unset `autoSessionTracking` and to remove the `browserSessionIntegration` in browser environments, or in server environments configure the `httpIntegration` with the `trackIncomingRequestsAsSessions` option set to `false`. +- **The metrics API has been removed from the SDK.** + +The Sentry metrics beta has ended and the metrics API has been removed from the SDK. Learn more in [help center docs](https://sentry.zendesk.com/hc/en-us/articles/26369339769883-Metrics-Beta-Ended-on-October-7th). + ## `@sentry/utils` - **The `@sentry/utils` package has been deprecated. Import everything from `@sentry/core` instead.** diff --git a/package.json b/package.json index e948ae773c72..c326f88d1347 100644 --- a/package.json +++ b/package.json @@ -44,9 +44,9 @@ "yalc:publish": "lerna run yalc:publish" }, "volta": { - "node": "18.20.3", + "node": "18.20.5", "yarn": "1.22.22", - "pnpm": "9.4.0" + "pnpm": "9.15.0" }, "workspaces": [ "packages/angular", @@ -112,7 +112,7 @@ "@size-limit/webpack": "~11.1.6", "@types/jest": "^27.4.1", "@types/jsdom": "^21.1.6", - "@types/node": "^14.18.0", + "@types/node": "^18.19.1", "@vitest/coverage-v8": "^1.6.0", "deepmerge": "^4.2.2", "downlevel-dts": "~0.11.0", diff --git a/packages/angular/README.md b/packages/angular/README.md index 42ee54a8d81c..95e0379480d7 100644 --- a/packages/angular/README.md +++ b/packages/angular/README.md @@ -17,7 +17,7 @@ ## Angular Version Compatibility -This SDK officially supports Angular 15 to 17. +This SDK officially supports Angular 14 to 19. If you're using an older Angular version please check the [compatibility table in the docs](https://docs.sentry.io/platforms/javascript/guides/angular/#angular-version-compatibility). @@ -33,24 +33,17 @@ in `@sentry/browser` can be imported from `@sentry/angular`. To use this SDK, call `Sentry.init(options)` before you bootstrap your Angular application. ```javascript -import { enableProdMode } from '@angular/core'; -import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; +import { bootstrapApplication } from '@angular/platform-browser'; import { init } from '@sentry/angular'; -import { AppModule } from './app/app.module'; +import { AppComponent } from './app/app.component'; init({ dsn: '__DSN__', // ... }); -// ... - -enableProdMode(); -platformBrowserDynamic() - .bootstrapModule(AppModule) - .then(success => console.log(`Bootstrap success`)) - .catch(err => console.error(err)); +bootstrapApplication(AppComponent, appConfig); ``` ### ErrorHandler @@ -58,10 +51,22 @@ platformBrowserDynamic() `@sentry/angular` exports a function to instantiate an ErrorHandler provider that will automatically send Javascript errors captured by the Angular's error handler. -```javascript -import { NgModule, ErrorHandler } from '@angular/core'; +```ts +import { ApplicationConfig, NgModule, ErrorHandler } from '@angular/core'; import { createErrorHandler } from '@sentry/angular'; +export const appConfig: ApplicationConfig = { + providers: [ + { + provide: ErrorHandler, + useValue: createErrorHandler({ + showDialog: true, + }), + }, + ], +}; + +// Or using an old module approach: @NgModule({ // ... providers: [ @@ -104,42 +109,27 @@ init({ }); ``` -2. Register `SentryTrace` as a provider in Angular's DI system, with a `Router` as its dependency: +2. Inject the `TraceService` in the `APP_INITIALIZER`: -```javascript -import { NgModule } from '@angular/core'; -import { Router } from '@angular/router'; -import { TraceService } from '@sentry/angular'; +```ts +import { ApplicationConfig, APP_INITIALIZER, provideAppInitializer } from '@angular/core'; -@NgModule({ - // ... +export const appConfig: ApplicationConfig = { providers: [ { - provide: TraceService, - deps: [Router], + provide: APP_INITIALIZER, + useFactory: () => () => {}, + deps: [TraceService], + multi: true, }, - ], - // ... -}) -export class AppModule {} -``` - -3. Either require the `TraceService` from inside `AppModule` or use `APP_INITIALIZER` to force-instantiate Tracing. - -```javascript -@NgModule({ - // ... -}) -export class AppModule { - constructor(trace: TraceService) {} -} -``` - -or -```javascript -import { APP_INITIALIZER } from '@angular/core'; + // Starting with Angular 19, we can use `provideAppInitializer` + // instead of directly providing `APP_INITIALIZER` (deprecated): + provideAppInitializer(() => inject(TraceService)), + ], +}; +// Or using an old module approach: @NgModule({ // ... providers: [ @@ -149,6 +139,10 @@ import { APP_INITIALIZER } from '@angular/core'; deps: [TraceService], multi: true, }, + + // Starting with Angular 19, we can use `provideAppInitializer` + // instead of directly providing `APP_INITIALIZER` (deprecated): + provideAppInitializer(() => inject(TraceService)), ], // ... }) @@ -161,15 +155,15 @@ To track Angular components as part of your transactions, you have 3 options. _TraceDirective:_ used to track a duration between `OnInit` and `AfterViewInit` lifecycle hooks in template: -```javascript +```ts import { TraceModule } from '@sentry/angular'; -@NgModule({ - // ... +@Component({ + selector: 'some-component', imports: [TraceModule], // ... }) -export class AppModule {} +export class SomeComponentThatUsesTraceDirective {} ``` Then, inside your component's template (keep in mind that the directive's name attribute is required): diff --git a/packages/angular/package.json b/packages/angular/package.json index 06bb0492c2f7..1ec948299d01 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "type": "module", "module": "build/fesm2015/sentry-angular.mjs", @@ -35,6 +35,7 @@ "@angular/platform-browser": "^14.3.0", "@angular/platform-browser-dynamic": "^14.3.0", "@angular/router": "^14.3.0", + "@types/node": "^14.8.0", "ng-packagr": "^14.2.2", "rxjs": "7.8.1", "typescript": "4.6.4", diff --git a/packages/astro/package.json b/packages/astro/package.json index 43c374a766cc..3d52f1145cd4 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -14,7 +14,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=18.14.1" + "node": ">=18.19.1" }, "type": "module", "files": [ diff --git a/packages/astro/src/index.server.ts b/packages/astro/src/index.server.ts index 3fe0c0001715..c5f3f74699d6 100644 --- a/packages/astro/src/index.server.ts +++ b/packages/astro/src/index.server.ts @@ -78,8 +78,6 @@ export { localVariablesIntegration, lruMemoizerIntegration, makeNodeTransport, - // eslint-disable-next-line deprecation/deprecation - metrics, modulesIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/astro/src/index.types.ts b/packages/astro/src/index.types.ts index ce87a51c3af7..01be44660cb9 100644 --- a/packages/astro/src/index.types.ts +++ b/packages/astro/src/index.types.ts @@ -10,7 +10,6 @@ import type { NodeOptions } from '@sentry/node'; import type { Client, Integration, Options, StackParser } from '@sentry/core'; import type * as clientSdk from './index.client'; -import type * as serverSdk from './index.server'; import sentryAstro from './index.server'; /** Initializes Sentry Astro SDK */ @@ -32,6 +31,4 @@ export declare const continueTrace: typeof clientSdk.continueTrace; export declare const Span: clientSdk.Span; -// eslint-disable-next-line deprecation/deprecation -export declare const metrics: typeof clientSdk.metrics & typeof serverSdk; export default sentryAstro; diff --git a/packages/aws-serverless/package.json b/packages/aws-serverless/package.json index 856a7dc4f51f..716b1c3fa5f7 100644 --- a/packages/aws-serverless/package.json +++ b/packages/aws-serverless/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build/npm", @@ -73,7 +73,7 @@ "@types/aws-lambda": "^8.10.62" }, "devDependencies": { - "@types/node": "^14.18.0" + "@types/node": "^18.19.1" }, "scripts": { "build": "run-p build:transpile build:types build:bundle", diff --git a/packages/aws-serverless/src/index.ts b/packages/aws-serverless/src/index.ts index d486ba9f68a7..c50d796415e9 100644 --- a/packages/aws-serverless/src/index.ts +++ b/packages/aws-serverless/src/index.ts @@ -76,8 +76,6 @@ export { continueTrace, getAutoPerformanceIntegrations, cron, - // eslint-disable-next-line deprecation/deprecation - metrics, parameterize, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, diff --git a/packages/browser-utils/package.json b/packages/browser-utils/package.json index 15d5bde00065..57730a1032f2 100644 --- a/packages/browser-utils/package.json +++ b/packages/browser-utils/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/browser/package.json b/packages/browser/package.json index f588f2801eb0..bb659245699e 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build/npm" diff --git a/packages/browser/src/index.bundle.feedback.ts b/packages/browser/src/index.bundle.feedback.ts index c6f75c03d9d1..957583d79eeb 100644 --- a/packages/browser/src/index.bundle.feedback.ts +++ b/packages/browser/src/index.bundle.feedback.ts @@ -1,4 +1,4 @@ -import { browserTracingIntegrationShim, metricsShim, replayIntegrationShim } from '@sentry-internal/integration-shims'; +import { browserTracingIntegrationShim, replayIntegrationShim } from '@sentry-internal/integration-shims'; import { feedbackAsyncIntegration } from './feedbackAsync'; export * from './index.bundle.base'; @@ -10,7 +10,6 @@ export { feedbackAsyncIntegration as feedbackAsyncIntegration, feedbackAsyncIntegration as feedbackIntegration, replayIntegrationShim as replayIntegration, - metricsShim as metrics, }; export { captureFeedback } from '@sentry/core'; diff --git a/packages/browser/src/index.bundle.replay.ts b/packages/browser/src/index.bundle.replay.ts index 2c1c8f0de424..86dc0fba7d25 100644 --- a/packages/browser/src/index.bundle.replay.ts +++ b/packages/browser/src/index.bundle.replay.ts @@ -1,8 +1,4 @@ -import { - browserTracingIntegrationShim, - feedbackIntegrationShim, - metricsShim, -} from '@sentry-internal/integration-shims'; +import { browserTracingIntegrationShim, feedbackIntegrationShim } from '@sentry-internal/integration-shims'; export * from './index.bundle.base'; @@ -12,5 +8,4 @@ export { browserTracingIntegrationShim as browserTracingIntegration, feedbackIntegrationShim as feedbackAsyncIntegration, feedbackIntegrationShim as feedbackIntegration, - metricsShim as metrics, }; diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index 6d86f90e01cc..a16f07bafaf2 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -4,8 +4,6 @@ registerSpanErrorInstrumentation(); export * from './index.bundle.base'; -export * from './metrics'; - export { getActiveSpan, getRootSpan, diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index a0fa6660b227..37f0da34ae25 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -4,8 +4,6 @@ registerSpanErrorInstrumentation(); export * from './index.bundle.base'; -export * from './metrics'; - export { getActiveSpan, getRootSpan, diff --git a/packages/browser/src/index.bundle.tracing.ts b/packages/browser/src/index.bundle.tracing.ts index 8115e628aa89..d540ff0bd6f9 100644 --- a/packages/browser/src/index.bundle.tracing.ts +++ b/packages/browser/src/index.bundle.tracing.ts @@ -5,8 +5,6 @@ registerSpanErrorInstrumentation(); export * from './index.bundle.base'; -export * from './metrics'; - export { getActiveSpan, getRootSpan, diff --git a/packages/browser/src/index.bundle.ts b/packages/browser/src/index.bundle.ts index 38787264f9b0..5004b376cd46 100644 --- a/packages/browser/src/index.bundle.ts +++ b/packages/browser/src/index.bundle.ts @@ -1,7 +1,6 @@ import { browserTracingIntegrationShim, feedbackIntegrationShim, - metricsShim, replayIntegrationShim, } from '@sentry-internal/integration-shims'; @@ -12,5 +11,4 @@ export { feedbackIntegrationShim as feedbackAsyncIntegration, feedbackIntegrationShim as feedbackIntegration, replayIntegrationShim as replayIntegration, - metricsShim as metrics, }; diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 94e090692a4e..56c7dd449602 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -31,8 +31,6 @@ import { feedbackSyncIntegration } from './feedbackSync'; export { feedbackAsyncIntegration, feedbackSyncIntegration, feedbackSyncIntegration as feedbackIntegration }; export { getFeedback, sendFeedback } from '@sentry-internal/feedback'; -export * from './metrics'; - export { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './tracing/request'; export { browserTracingIntegration, diff --git a/packages/browser/src/metrics.ts b/packages/browser/src/metrics.ts deleted file mode 100644 index 96f56988c485..000000000000 --- a/packages/browser/src/metrics.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { BrowserMetricsAggregator, metrics as metricsCore } from '@sentry/core'; -import type { DurationUnit, MetricData, Metrics } from '@sentry/core'; - -/** - * Adds a value to a counter metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function increment(name: string, value: number = 1, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.increment(BrowserMetricsAggregator, name, value, data); -} - -/** - * Adds a value to a distribution metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function distribution(name: string, value: number, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.distribution(BrowserMetricsAggregator, name, value, data); -} - -/** - * Adds a value to a set metric. Value must be a string or integer. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function set(name: string, value: number | string, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.set(BrowserMetricsAggregator, name, value, data); -} - -/** - * Adds a value to a gauge metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function gauge(name: string, value: number, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.gauge(BrowserMetricsAggregator, name, value, data); -} - -/** - * Adds a timing metric. - * The metric is added as a distribution metric. - * - * You can either directly capture a numeric `value`, or wrap a callback function in `timing`. - * In the latter case, the duration of the callback execution will be captured as a span & a metric. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function timing(name: string, value: number, unit?: DurationUnit, data?: Omit): void; -function timing(name: string, callback: () => T, unit?: DurationUnit, data?: Omit): T; -function timing( - name: string, - value: number | (() => T), - unit: DurationUnit = 'second', - data?: Omit, -): T | void { - // eslint-disable-next-line deprecation/deprecation - return metricsCore.timing(BrowserMetricsAggregator, name, value, unit, data); -} - -/** - * The metrics API is used to capture custom metrics in Sentry. - * - * @deprecated The Sentry metrics beta has ended. This export will be removed in a future release. - */ -export const metrics: Metrics = { - increment, - distribution, - set, - gauge, - timing, -}; diff --git a/packages/bun/package.json b/packages/bun/package.json index ce1c85cbcd0f..753046173a9c 100644 --- a/packages/bun/package.json +++ b/packages/bun/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/bun/src/index.ts b/packages/bun/src/index.ts index 94c40505ff41..6b172c998d64 100644 --- a/packages/bun/src/index.ts +++ b/packages/bun/src/index.ts @@ -99,8 +99,6 @@ export { continueTrace, getAutoPerformanceIntegrations, cron, - // eslint-disable-next-line deprecation/deprecation - metrics, parameterize, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, diff --git a/packages/cloudflare/package.json b/packages/cloudflare/package.json index efec51c5c0f5..aa84ff96c596 100644 --- a/packages/cloudflare/package.json +++ b/packages/cloudflare/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" @@ -46,7 +46,7 @@ }, "devDependencies": { "@cloudflare/workers-types": "^4.20240725.0", - "@types/node": "^14.18.0", + "@types/node": "^18.19.1", "wrangler": "^3.67.1" }, "scripts": { diff --git a/packages/cloudflare/src/index.ts b/packages/cloudflare/src/index.ts index 38f0565e61c3..8dd5ba50a623 100644 --- a/packages/cloudflare/src/index.ts +++ b/packages/cloudflare/src/index.ts @@ -67,8 +67,6 @@ export { withActiveSpan, getSpanDescendants, continueTrace, - // eslint-disable-next-line deprecation/deprecation - metrics, functionToStringIntegration, inboundFiltersIntegration, linkedErrorsIntegration, diff --git a/packages/core/package.json b/packages/core/package.json index ab43b79117b9..c9079fcf5a14 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/core/src/carrier.ts b/packages/core/src/carrier.ts index e8bffa63b660..5136121cb8ae 100644 --- a/packages/core/src/carrier.ts +++ b/packages/core/src/carrier.ts @@ -1,7 +1,6 @@ import type { AsyncContextStack } from './asyncContext/stackStrategy'; import type { AsyncContextStrategy } from './asyncContext/types'; import type { Scope } from './scope'; -import type { Client, MetricsAggregator } from './types-hoist'; import type { Logger } from './utils-hoist/logger'; import { SDK_VERSION } from './utils-hoist/version'; import { GLOBAL_OBJ } from './utils-hoist/worldwide'; @@ -25,7 +24,6 @@ export interface SentryCarrier { globalScope?: Scope; defaultIsolationScope?: Scope; defaultCurrentScope?: Scope; - globalMetricsAggregators?: WeakMap | undefined; logger?: Logger; /** Overwrites TextEncoder used in `@sentry/core`, need for `react-native@0.73` and older */ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index d7c4785cc3e2..98cb1bda04e9 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -101,13 +101,7 @@ export { extraErrorDataIntegration } from './integrations/extraerrordata'; export { rewriteFramesIntegration } from './integrations/rewriteframes'; export { zodErrorsIntegration } from './integrations/zoderrors'; export { thirdPartyErrorFilterIntegration } from './integrations/third-party-errors-filter'; -// eslint-disable-next-line deprecation/deprecation -export { metrics } from './metrics/exports'; export { profiler } from './profiling'; -// eslint-disable-next-line deprecation/deprecation -export { metricsDefault } from './metrics/exports-default'; -export { BrowserMetricsAggregator } from './metrics/browser-aggregator'; -export { getMetricSummaryJsonForSpan } from './metrics/metric-summary'; export { // eslint-disable-next-line deprecation/deprecation addTracingHeadersToFetchRequest, diff --git a/packages/core/src/metrics/aggregator.ts b/packages/core/src/metrics/aggregator.ts deleted file mode 100644 index 972c6b3336ad..000000000000 --- a/packages/core/src/metrics/aggregator.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { Client, MeasurementUnit, MetricsAggregator as MetricsAggregatorBase, Primitive } from '../types-hoist'; -import { timestampInSeconds } from '../utils-hoist/time'; -import { updateMetricSummaryOnActiveSpan } from '../utils/spanUtils'; -import { DEFAULT_FLUSH_INTERVAL, MAX_WEIGHT, SET_METRIC_TYPE } from './constants'; -import { captureAggregateMetrics } from './envelope'; -import { METRIC_MAP } from './instance'; -import type { MetricBucket, MetricType } from './types'; -import { getBucketKey, sanitizeMetricKey, sanitizeTags, sanitizeUnit } from './utils'; - -/** - * A metrics aggregator that aggregates metrics in memory and flushes them periodically. - */ -export class MetricsAggregator implements MetricsAggregatorBase { - // TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets - // when the aggregator is garbage collected. - // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry - private _buckets: MetricBucket; - - // Different metrics have different weights. We use this to limit the number of metrics - // that we store in memory. - private _bucketsTotalWeight; - - // We adjust the type here to add the `unref()` part, as setInterval can technically return a number or a NodeJS.Timer - private readonly _interval: ReturnType & { unref?: () => void }; - - // SDKs are required to shift the flush interval by random() * rollup_in_seconds. - // That shift is determined once per startup to create jittering. - private readonly _flushShift: number; - - // An SDK is required to perform force flushing ahead of scheduled time if the memory - // pressure is too high. There is no rule for this other than that SDKs should be tracking - // abstract aggregation complexity (eg: a counter only carries a single float, whereas a - // distribution is a float per emission). - // - // Force flush is used on either shutdown, flush() or when we exceed the max weight. - private _forceFlush: boolean; - - public constructor(private readonly _client: Client) { - this._buckets = new Map(); - this._bucketsTotalWeight = 0; - - this._interval = setInterval(() => this._flush(), DEFAULT_FLUSH_INTERVAL); - if (this._interval.unref) { - this._interval.unref(); - } - - this._flushShift = Math.floor((Math.random() * DEFAULT_FLUSH_INTERVAL) / 1000); - this._forceFlush = false; - } - - /** - * @inheritDoc - */ - public add( - metricType: MetricType, - unsanitizedName: string, - value: number | string, - unsanitizedUnit: MeasurementUnit = 'none', - unsanitizedTags: Record = {}, - maybeFloatTimestamp = timestampInSeconds(), - ): void { - const timestamp = Math.floor(maybeFloatTimestamp); - const name = sanitizeMetricKey(unsanitizedName); - const tags = sanitizeTags(unsanitizedTags); - const unit = sanitizeUnit(unsanitizedUnit as string); - - const bucketKey = getBucketKey(metricType, name, unit, tags); - - let bucketItem = this._buckets.get(bucketKey); - // If this is a set metric, we need to calculate the delta from the previous weight. - const previousWeight = bucketItem && metricType === SET_METRIC_TYPE ? bucketItem.metric.weight : 0; - - if (bucketItem) { - bucketItem.metric.add(value); - // TODO(abhi): Do we need this check? - if (bucketItem.timestamp < timestamp) { - bucketItem.timestamp = timestamp; - } - } else { - bucketItem = { - // @ts-expect-error we don't need to narrow down the type of value here, saves bundle size. - metric: new METRIC_MAP[metricType](value), - timestamp, - metricType, - name, - unit, - tags, - }; - this._buckets.set(bucketKey, bucketItem); - } - - // If value is a string, it's a set metric so calculate the delta from the previous weight. - const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value; - updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey); - - // We need to keep track of the total weight of the buckets so that we can - // flush them when we exceed the max weight. - this._bucketsTotalWeight += bucketItem.metric.weight; - - if (this._bucketsTotalWeight >= MAX_WEIGHT) { - this.flush(); - } - } - - /** - * Flushes the current metrics to the transport via the transport. - */ - public flush(): void { - this._forceFlush = true; - this._flush(); - } - - /** - * Shuts down metrics aggregator and clears all metrics. - */ - public close(): void { - this._forceFlush = true; - clearInterval(this._interval); - this._flush(); - } - - /** - * Flushes the buckets according to the internal state of the aggregator. - * If it is a force flush, which happens on shutdown, it will flush all buckets. - * Otherwise, it will only flush buckets that are older than the flush interval, - * and according to the flush shift. - * - * This function mutates `_forceFlush` and `_bucketsTotalWeight` properties. - */ - private _flush(): void { - // TODO(@anonrig): Add Atomics for locking to avoid having force flush and regular flush - // running at the same time. - // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Atomics - - // This path eliminates the need for checking for timestamps since we're forcing a flush. - // Remember to reset the flag, or it will always flush all metrics. - if (this._forceFlush) { - this._forceFlush = false; - this._bucketsTotalWeight = 0; - this._captureMetrics(this._buckets); - this._buckets.clear(); - return; - } - const cutoffSeconds = Math.floor(timestampInSeconds()) - DEFAULT_FLUSH_INTERVAL / 1000 - this._flushShift; - // TODO(@anonrig): Optimization opportunity. - // Convert this map to an array and store key in the bucketItem. - const flushedBuckets: MetricBucket = new Map(); - for (const [key, bucket] of this._buckets) { - if (bucket.timestamp <= cutoffSeconds) { - flushedBuckets.set(key, bucket); - this._bucketsTotalWeight -= bucket.metric.weight; - } - } - - for (const [key] of flushedBuckets) { - this._buckets.delete(key); - } - - this._captureMetrics(flushedBuckets); - } - - /** - * Only captures a subset of the buckets passed to this function. - * @param flushedBuckets - */ - private _captureMetrics(flushedBuckets: MetricBucket): void { - if (flushedBuckets.size > 0) { - // TODO(@anonrig): Optimization opportunity. - // This copy operation can be avoided if we store the key in the bucketItem. - const buckets = Array.from(flushedBuckets).map(([, bucketItem]) => bucketItem); - captureAggregateMetrics(this._client, buckets); - } - } -} diff --git a/packages/core/src/metrics/browser-aggregator.ts b/packages/core/src/metrics/browser-aggregator.ts deleted file mode 100644 index fca72f48f40f..000000000000 --- a/packages/core/src/metrics/browser-aggregator.ts +++ /dev/null @@ -1,96 +0,0 @@ -import type { Client, MeasurementUnit, MetricsAggregator, Primitive } from '../types-hoist'; -import { timestampInSeconds } from '../utils-hoist/time'; -import { updateMetricSummaryOnActiveSpan } from '../utils/spanUtils'; -import { DEFAULT_BROWSER_FLUSH_INTERVAL, SET_METRIC_TYPE } from './constants'; -import { captureAggregateMetrics } from './envelope'; -import { METRIC_MAP } from './instance'; -import type { MetricBucket, MetricType } from './types'; -import { getBucketKey, sanitizeMetricKey, sanitizeTags, sanitizeUnit } from './utils'; - -/** - * A simple metrics aggregator that aggregates metrics in memory and flushes them periodically. - * Default flush interval is 5 seconds. - * - * @experimental This API is experimental and might change in the future. - */ -export class BrowserMetricsAggregator implements MetricsAggregator { - // TODO(@anonrig): Use FinalizationRegistry to have a proper way of flushing the buckets - // when the aggregator is garbage collected. - // Ref: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/FinalizationRegistry - private _buckets: MetricBucket; - private readonly _interval: ReturnType; - - public constructor(private readonly _client: Client) { - this._buckets = new Map(); - this._interval = setInterval(() => this.flush(), DEFAULT_BROWSER_FLUSH_INTERVAL); - } - - /** - * @inheritDoc - */ - public add( - metricType: MetricType, - unsanitizedName: string, - value: number | string, - unsanitizedUnit: MeasurementUnit | undefined = 'none', - unsanitizedTags: Record | undefined = {}, - maybeFloatTimestamp: number | undefined = timestampInSeconds(), - ): void { - const timestamp = Math.floor(maybeFloatTimestamp); - const name = sanitizeMetricKey(unsanitizedName); - const tags = sanitizeTags(unsanitizedTags); - const unit = sanitizeUnit(unsanitizedUnit as string); - - const bucketKey = getBucketKey(metricType, name, unit, tags); - - let bucketItem = this._buckets.get(bucketKey); - // If this is a set metric, we need to calculate the delta from the previous weight. - const previousWeight = bucketItem && metricType === SET_METRIC_TYPE ? bucketItem.metric.weight : 0; - - if (bucketItem) { - bucketItem.metric.add(value); - // TODO(abhi): Do we need this check? - if (bucketItem.timestamp < timestamp) { - bucketItem.timestamp = timestamp; - } - } else { - bucketItem = { - // @ts-expect-error we don't need to narrow down the type of value here, saves bundle size. - metric: new METRIC_MAP[metricType](value), - timestamp, - metricType, - name, - unit, - tags, - }; - this._buckets.set(bucketKey, bucketItem); - } - - // If value is a string, it's a set metric so calculate the delta from the previous weight. - const val = typeof value === 'string' ? bucketItem.metric.weight - previousWeight : value; - updateMetricSummaryOnActiveSpan(metricType, name, val, unit, unsanitizedTags, bucketKey); - } - - /** - * @inheritDoc - */ - public flush(): void { - // short circuit if buckets are empty. - if (this._buckets.size === 0) { - return; - } - - const metricBuckets = Array.from(this._buckets.values()); - captureAggregateMetrics(this._client, metricBuckets); - - this._buckets.clear(); - } - - /** - * @inheritDoc - */ - public close(): void { - clearInterval(this._interval); - this.flush(); - } -} diff --git a/packages/core/src/metrics/constants.ts b/packages/core/src/metrics/constants.ts deleted file mode 100644 index ae1cd968723c..000000000000 --- a/packages/core/src/metrics/constants.ts +++ /dev/null @@ -1,21 +0,0 @@ -export const COUNTER_METRIC_TYPE = 'c' as const; -export const GAUGE_METRIC_TYPE = 'g' as const; -export const SET_METRIC_TYPE = 's' as const; -export const DISTRIBUTION_METRIC_TYPE = 'd' as const; - -/** - * This does not match spec in https://develop.sentry.dev/sdk/metrics - * but was chosen to optimize for the most common case in browser environments. - */ -export const DEFAULT_BROWSER_FLUSH_INTERVAL = 5000; - -/** - * SDKs are required to bucket into 10 second intervals (rollup in seconds) - * which is the current lower bound of metric accuracy. - */ -export const DEFAULT_FLUSH_INTERVAL = 10000; - -/** - * The maximum number of metrics that should be stored in memory. - */ -export const MAX_WEIGHT = 10000; diff --git a/packages/core/src/metrics/envelope.ts b/packages/core/src/metrics/envelope.ts deleted file mode 100644 index 7c1a4d612577..000000000000 --- a/packages/core/src/metrics/envelope.ts +++ /dev/null @@ -1,58 +0,0 @@ -import type { Client, DsnComponents, MetricBucketItem, SdkMetadata, StatsdEnvelope, StatsdItem } from '../types-hoist'; -import { dsnToString } from '../utils-hoist/dsn'; -import { createEnvelope } from '../utils-hoist/envelope'; -import { logger } from '../utils-hoist/logger'; -import { serializeMetricBuckets } from './utils'; - -/** - * Captures aggregated metrics to the supplied client. - */ -export function captureAggregateMetrics(client: Client, metricBucketItems: Array): void { - logger.log(`Flushing aggregated metrics, number of metrics: ${metricBucketItems.length}`); - const dsn = client.getDsn(); - const metadata = client.getSdkMetadata(); - const tunnel = client.getOptions().tunnel; - - const metricsEnvelope = createMetricEnvelope(metricBucketItems, dsn, metadata, tunnel); - - // sendEnvelope should not throw - // eslint-disable-next-line @typescript-eslint/no-floating-promises - client.sendEnvelope(metricsEnvelope); -} - -/** - * Create envelope from a metric aggregate. - */ -export function createMetricEnvelope( - metricBucketItems: Array, - dsn?: DsnComponents, - metadata?: SdkMetadata, - tunnel?: string, -): StatsdEnvelope { - const headers: StatsdEnvelope[0] = { - sent_at: new Date().toISOString(), - }; - - if (metadata && metadata.sdk) { - headers.sdk = { - name: metadata.sdk.name, - version: metadata.sdk.version, - }; - } - - if (!!tunnel && dsn) { - headers.dsn = dsnToString(dsn); - } - - const item = createMetricEnvelopeItem(metricBucketItems); - return createEnvelope(headers, [item]); -} - -function createMetricEnvelopeItem(metricBucketItems: MetricBucketItem[]): StatsdItem { - const payload = serializeMetricBuckets(metricBucketItems); - const metricHeaders: StatsdItem[0] = { - type: 'statsd', - length: payload.length, - }; - return [metricHeaders, payload]; -} diff --git a/packages/core/src/metrics/exports-default.ts b/packages/core/src/metrics/exports-default.ts deleted file mode 100644 index e071015b73f1..000000000000 --- a/packages/core/src/metrics/exports-default.ts +++ /dev/null @@ -1,97 +0,0 @@ -import type { - Client, - DurationUnit, - MetricData, - Metrics, - MetricsAggregator as MetricsAggregatorInterface, -} from '../types-hoist'; -import { MetricsAggregator } from './aggregator'; -import { metrics as metricsCore } from './exports'; - -/** - * Adds a value to a counter metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function increment(name: string, value: number = 1, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.increment(MetricsAggregator, name, value, data); -} - -/** - * Adds a value to a distribution metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function distribution(name: string, value: number, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.distribution(MetricsAggregator, name, value, data); -} - -/** - * Adds a value to a set metric. Value must be a string or integer. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function set(name: string, value: number | string, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.set(MetricsAggregator, name, value, data); -} - -/** - * Adds a value to a gauge metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function gauge(name: string, value: number, data?: MetricData): void { - // eslint-disable-next-line deprecation/deprecation - metricsCore.gauge(MetricsAggregator, name, value, data); -} - -/** - * Adds a timing metric. - * The metric is added as a distribution metric. - * - * You can either directly capture a numeric `value`, or wrap a callback function in `timing`. - * In the latter case, the duration of the callback execution will be captured as a span & a metric. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function timing(name: string, value: number, unit?: DurationUnit, data?: Omit): void; -function timing(name: string, callback: () => T, unit?: DurationUnit, data?: Omit): T; -function timing( - name: string, - value: number | (() => T), - unit: DurationUnit = 'second', - data?: Omit, -): T | void { - // eslint-disable-next-line deprecation/deprecation - return metricsCore.timing(MetricsAggregator, name, value, unit, data); -} - -/** - * Returns the metrics aggregator for a given client. - */ -function getMetricsAggregatorForClient(client: Client): MetricsAggregatorInterface { - // eslint-disable-next-line deprecation/deprecation - return metricsCore.getMetricsAggregatorForClient(client, MetricsAggregator); -} - -/** - * The metrics API is used to capture custom metrics in Sentry. - * - * @deprecated The Sentry metrics beta has ended. This export will be removed in a future release. - */ -export const metricsDefault: Metrics & { - getMetricsAggregatorForClient: typeof getMetricsAggregatorForClient; -} = { - increment, - distribution, - set, - gauge, - timing, - /** - * @ignore This is for internal use only. - */ - getMetricsAggregatorForClient, -}; diff --git a/packages/core/src/metrics/exports.ts b/packages/core/src/metrics/exports.ts deleted file mode 100644 index 03d2ef90efe8..000000000000 --- a/packages/core/src/metrics/exports.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { getGlobalSingleton } from '../carrier'; -import { getClient } from '../currentScopes'; -import { DEBUG_BUILD } from '../debug-build'; -import { startSpanManual } from '../tracing'; -import type { Client, DurationUnit, MetricData, MetricsAggregator as MetricsAggregatorInterface } from '../types-hoist'; -import { logger } from '../utils-hoist/logger'; -import { timestampInSeconds } from '../utils-hoist/time'; -import { handleCallbackErrors } from '../utils/handleCallbackErrors'; -import { getActiveSpan, getRootSpan, spanToJSON } from '../utils/spanUtils'; -import { COUNTER_METRIC_TYPE, DISTRIBUTION_METRIC_TYPE, GAUGE_METRIC_TYPE, SET_METRIC_TYPE } from './constants'; -import type { MetricType } from './types'; - -type MetricsAggregatorConstructor = { - new (client: Client): MetricsAggregatorInterface; -}; - -/** - * Gets the metrics aggregator for a given client. - * @param client The client for which to get the metrics aggregator. - * @param Aggregator Optional metrics aggregator class to use to create an aggregator if one does not exist. - */ -function getMetricsAggregatorForClient( - client: Client, - Aggregator: MetricsAggregatorConstructor, -): MetricsAggregatorInterface { - const globalMetricsAggregators = getGlobalSingleton( - 'globalMetricsAggregators', - () => new WeakMap(), - ); - - const aggregator = globalMetricsAggregators.get(client); - if (aggregator) { - return aggregator; - } - - const newAggregator = new Aggregator(client); - client.on('flush', () => newAggregator.flush()); - client.on('close', () => newAggregator.close()); - globalMetricsAggregators.set(client, newAggregator); - - return newAggregator; -} - -function addToMetricsAggregator( - Aggregator: MetricsAggregatorConstructor, - metricType: MetricType, - name: string, - value: number | string, - data: MetricData | undefined = {}, -): void { - const client = data.client || getClient(); - - if (!client) { - return; - } - - const span = getActiveSpan(); - const rootSpan = span ? getRootSpan(span) : undefined; - const transactionName = rootSpan && spanToJSON(rootSpan).description; - - const { unit, tags, timestamp } = data; - const { release, environment } = client.getOptions(); - const metricTags: Record = {}; - if (release) { - metricTags.release = release; - } - if (environment) { - metricTags.environment = environment; - } - if (transactionName) { - metricTags.transaction = transactionName; - } - - DEBUG_BUILD && logger.log(`Adding value of ${value} to ${metricType} metric ${name}`); - - const aggregator = getMetricsAggregatorForClient(client, Aggregator); - aggregator.add(metricType, name, value, unit, { ...metricTags, ...tags }, timestamp); -} - -/** - * Adds a value to a counter metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function increment(aggregator: MetricsAggregatorConstructor, name: string, value: number = 1, data?: MetricData): void { - addToMetricsAggregator(aggregator, COUNTER_METRIC_TYPE, name, ensureNumber(value), data); -} - -/** - * Adds a value to a distribution metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function distribution(aggregator: MetricsAggregatorConstructor, name: string, value: number, data?: MetricData): void { - addToMetricsAggregator(aggregator, DISTRIBUTION_METRIC_TYPE, name, ensureNumber(value), data); -} - -/** - * Adds a timing metric. - * The metric is added as a distribution metric. - * - * You can either directly capture a numeric `value`, or wrap a callback function in `timing`. - * In the latter case, the duration of the callback execution will be captured as a span & a metric. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function timing( - aggregator: MetricsAggregatorConstructor, - name: string, - value: number | (() => T), - unit: DurationUnit = 'second', - data?: Omit, -): T | void { - // callback form - if (typeof value === 'function') { - const startTime = timestampInSeconds(); - - return startSpanManual( - { - op: 'metrics.timing', - name, - startTime, - onlyIfParent: true, - }, - span => { - return handleCallbackErrors( - () => value(), - () => { - // no special error handling necessary - }, - () => { - const endTime = timestampInSeconds(); - const timeDiff = endTime - startTime; - // eslint-disable-next-line deprecation/deprecation - distribution(aggregator, name, timeDiff, { ...data, unit: 'second' }); - span.end(endTime); - }, - ); - }, - ); - } - - // value form - // eslint-disable-next-line deprecation/deprecation - distribution(aggregator, name, value, { ...data, unit }); -} - -/** - * Adds a value to a set metric. Value must be a string or integer. - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function set(aggregator: MetricsAggregatorConstructor, name: string, value: number | string, data?: MetricData): void { - addToMetricsAggregator(aggregator, SET_METRIC_TYPE, name, value, data); -} - -/** - * Adds a value to a gauge metric - * - * @deprecated The Sentry metrics beta has ended. This method will be removed in a future release. - */ -function gauge(aggregator: MetricsAggregatorConstructor, name: string, value: number, data?: MetricData): void { - addToMetricsAggregator(aggregator, GAUGE_METRIC_TYPE, name, ensureNumber(value), data); -} - -/** - * The metrics API is used to capture custom metrics in Sentry. - * - * @deprecated The Sentry metrics beta has ended. This export will be removed in a future release. - */ -export const metrics = { - increment, - distribution, - set, - gauge, - timing, - /** - * @ignore This is for internal use only. - */ - getMetricsAggregatorForClient, -}; - -// Although this is typed to be a number, we try to handle strings as well here -function ensureNumber(number: number | string): number { - return typeof number === 'string' ? parseInt(number) : number; -} diff --git a/packages/core/src/metrics/instance.ts b/packages/core/src/metrics/instance.ts deleted file mode 100644 index 28b57ae7f75c..000000000000 --- a/packages/core/src/metrics/instance.ts +++ /dev/null @@ -1,128 +0,0 @@ -import type { MetricInstance } from '../types-hoist'; -import { COUNTER_METRIC_TYPE, DISTRIBUTION_METRIC_TYPE, GAUGE_METRIC_TYPE, SET_METRIC_TYPE } from './constants'; -import { simpleHash } from './utils'; - -/** - * A metric instance representing a counter. - */ -export class CounterMetric implements MetricInstance { - public constructor(private _value: number) {} - - /** @inheritDoc */ - public get weight(): number { - return 1; - } - - /** @inheritdoc */ - public add(value: number): void { - this._value += value; - } - - /** @inheritdoc */ - public toString(): string { - return `${this._value}`; - } -} - -/** - * A metric instance representing a gauge. - */ -export class GaugeMetric implements MetricInstance { - private _last: number; - private _min: number; - private _max: number; - private _sum: number; - private _count: number; - - public constructor(value: number) { - this._last = value; - this._min = value; - this._max = value; - this._sum = value; - this._count = 1; - } - - /** @inheritDoc */ - public get weight(): number { - return 5; - } - - /** @inheritdoc */ - public add(value: number): void { - this._last = value; - if (value < this._min) { - this._min = value; - } - if (value > this._max) { - this._max = value; - } - this._sum += value; - this._count++; - } - - /** @inheritdoc */ - public toString(): string { - return `${this._last}:${this._min}:${this._max}:${this._sum}:${this._count}`; - } -} - -/** - * A metric instance representing a distribution. - */ -export class DistributionMetric implements MetricInstance { - private _value: number[]; - - public constructor(first: number) { - this._value = [first]; - } - - /** @inheritDoc */ - public get weight(): number { - return this._value.length; - } - - /** @inheritdoc */ - public add(value: number): void { - this._value.push(value); - } - - /** @inheritdoc */ - public toString(): string { - return this._value.join(':'); - } -} - -/** - * A metric instance representing a set. - */ -export class SetMetric implements MetricInstance { - private _value: Set; - - public constructor(public first: number | string) { - this._value = new Set([first]); - } - - /** @inheritDoc */ - public get weight(): number { - return this._value.size; - } - - /** @inheritdoc */ - public add(value: number | string): void { - this._value.add(value); - } - - /** @inheritdoc */ - public toString(): string { - return Array.from(this._value) - .map(val => (typeof val === 'string' ? simpleHash(val) : val)) - .join(':'); - } -} - -export const METRIC_MAP = { - [COUNTER_METRIC_TYPE]: CounterMetric, - [GAUGE_METRIC_TYPE]: GaugeMetric, - [DISTRIBUTION_METRIC_TYPE]: DistributionMetric, - [SET_METRIC_TYPE]: SetMetric, -}; diff --git a/packages/core/src/metrics/metric-summary.ts b/packages/core/src/metrics/metric-summary.ts deleted file mode 100644 index e7a8a00c289a..000000000000 --- a/packages/core/src/metrics/metric-summary.ts +++ /dev/null @@ -1,82 +0,0 @@ -import type { MeasurementUnit, Span } from '../types-hoist'; -import type { MetricSummary } from '../types-hoist'; -import type { Primitive } from '../types-hoist'; -import { dropUndefinedKeys } from '../utils-hoist/object'; -import type { MetricType } from './types'; - -/** - * key: bucketKey - * value: [exportKey, MetricSummary] - */ -type MetricSummaryStorage = Map; - -const METRICS_SPAN_FIELD = '_sentryMetrics'; - -type SpanWithPotentialMetrics = Span & { - [METRICS_SPAN_FIELD]?: MetricSummaryStorage; -}; - -/** - * Fetches the metric summary if it exists for the passed span - */ -export function getMetricSummaryJsonForSpan(span: Span): Record> | undefined { - const storage = (span as SpanWithPotentialMetrics)[METRICS_SPAN_FIELD]; - - if (!storage) { - return undefined; - } - const output: Record> = {}; - - for (const [, [exportKey, summary]] of storage) { - const arr = output[exportKey] || (output[exportKey] = []); - arr.push(dropUndefinedKeys(summary)); - } - - return output; -} - -/** - * Updates the metric summary on a span. - */ -export function updateMetricSummaryOnSpan( - span: Span, - metricType: MetricType, - sanitizedName: string, - value: number, - unit: MeasurementUnit, - tags: Record, - bucketKey: string, -): void { - const existingStorage = (span as SpanWithPotentialMetrics)[METRICS_SPAN_FIELD]; - const storage = - existingStorage || - ((span as SpanWithPotentialMetrics)[METRICS_SPAN_FIELD] = new Map()); - - const exportKey = `${metricType}:${sanitizedName}@${unit}`; - const bucketItem = storage.get(bucketKey); - - if (bucketItem) { - const [, summary] = bucketItem; - storage.set(bucketKey, [ - exportKey, - { - min: Math.min(summary.min, value), - max: Math.max(summary.max, value), - count: (summary.count += 1), - sum: (summary.sum += value), - tags: summary.tags, - }, - ]); - } else { - storage.set(bucketKey, [ - exportKey, - { - min: value, - max: value, - count: 1, - sum: value, - tags, - }, - ]); - } -} diff --git a/packages/core/src/metrics/types.ts b/packages/core/src/metrics/types.ts deleted file mode 100644 index d1d01cd1abab..000000000000 --- a/packages/core/src/metrics/types.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { MetricBucketItem } from '../types-hoist'; -import type { COUNTER_METRIC_TYPE, DISTRIBUTION_METRIC_TYPE, GAUGE_METRIC_TYPE, SET_METRIC_TYPE } from './constants'; - -export type MetricType = - | typeof COUNTER_METRIC_TYPE - | typeof GAUGE_METRIC_TYPE - | typeof SET_METRIC_TYPE - | typeof DISTRIBUTION_METRIC_TYPE; - -// TODO(@anonrig): Convert this to WeakMap when we support ES6 and -// use FinalizationRegistry to flush the buckets when the aggregator is garbage collected. -export type MetricBucket = Map; diff --git a/packages/core/src/metrics/utils.ts b/packages/core/src/metrics/utils.ts deleted file mode 100644 index 903a185e27f3..000000000000 --- a/packages/core/src/metrics/utils.ts +++ /dev/null @@ -1,125 +0,0 @@ -import type { MeasurementUnit, MetricBucketItem, Primitive } from '../types-hoist'; -import { dropUndefinedKeys } from '../utils-hoist/object'; -import type { MetricType } from './types'; - -/** - * Generate bucket key from metric properties. - */ -export function getBucketKey( - metricType: MetricType, - name: string, - unit: MeasurementUnit, - tags: Record, -): string { - const stringifiedTags = Object.entries(dropUndefinedKeys(tags)).sort((a, b) => a[0].localeCompare(b[0])); - return `${metricType}${name}${unit}${stringifiedTags}`; -} - -/* eslint-disable no-bitwise */ -/** - * Simple hash function for strings. - */ -export function simpleHash(s: string): number { - let rv = 0; - for (let i = 0; i < s.length; i++) { - const c = s.charCodeAt(i); - rv = (rv << 5) - rv + c; - rv &= rv; - } - return rv >>> 0; -} -/* eslint-enable no-bitwise */ - -/** - * Serialize metrics buckets into a string based on statsd format. - * - * Example of format: - * metric.name@second:1:1.2|d|#a:value,b:anothervalue|T12345677 - * Segments: - * name: metric.name - * unit: second - * value: [1, 1.2] - * type of metric: d (distribution) - * tags: { a: value, b: anothervalue } - * timestamp: 12345677 - */ -export function serializeMetricBuckets(metricBucketItems: MetricBucketItem[]): string { - let out = ''; - for (const item of metricBucketItems) { - const tagEntries = Object.entries(item.tags); - const maybeTags = tagEntries.length > 0 ? `|#${tagEntries.map(([key, value]) => `${key}:${value}`).join(',')}` : ''; - out += `${item.name}@${item.unit}:${item.metric}|${item.metricType}${maybeTags}|T${item.timestamp}\n`; - } - return out; -} - -/** - * Sanitizes units - * - * These Regex's are straight from the normalisation docs: - * https://develop.sentry.dev/sdk/metrics/#normalization - */ -export function sanitizeUnit(unit: string): string { - return unit.replace(/[^\w]+/gi, '_'); -} - -/** - * Sanitizes metric keys - * - * These Regex's are straight from the normalisation docs: - * https://develop.sentry.dev/sdk/metrics/#normalization - */ -export function sanitizeMetricKey(key: string): string { - return key.replace(/[^\w\-.]+/gi, '_'); -} - -/** - * Sanitizes metric keys - * - * These Regex's are straight from the normalisation docs: - * https://develop.sentry.dev/sdk/metrics/#normalization - */ -function sanitizeTagKey(key: string): string { - return key.replace(/[^\w\-./]+/gi, ''); -} - -/** - * These Regex's are straight from the normalisation docs: - * https://develop.sentry.dev/sdk/metrics/#normalization - */ -const tagValueReplacements: [string, string][] = [ - ['\n', '\\n'], - ['\r', '\\r'], - ['\t', '\\t'], - ['\\', '\\\\'], - ['|', '\\u{7c}'], - [',', '\\u{2c}'], -]; - -function getCharOrReplacement(input: string): string { - for (const [search, replacement] of tagValueReplacements) { - if (input === search) { - return replacement; - } - } - - return input; -} - -function sanitizeTagValue(value: string): string { - return [...value].reduce((acc, char) => acc + getCharOrReplacement(char), ''); -} - -/** - * Sanitizes tags. - */ -export function sanitizeTags(unsanitizedTags: Record): Record { - const tags: Record = {}; - for (const key in unsanitizedTags) { - if (Object.prototype.hasOwnProperty.call(unsanitizedTags, key)) { - const sanitizedKey = sanitizeTagKey(key); - tags[sanitizedKey] = sanitizeTagValue(String(unsanitizedTags[key])); - } - } - return tags; -} diff --git a/packages/core/src/tracing/sentrySpan.ts b/packages/core/src/tracing/sentrySpan.ts index 9965261970f2..309f46ff874c 100644 --- a/packages/core/src/tracing/sentrySpan.ts +++ b/packages/core/src/tracing/sentrySpan.ts @@ -1,7 +1,6 @@ import { getClient, getCurrentScope } from '../currentScopes'; import { DEBUG_BUILD } from '../debug-build'; import { createSpanEnvelope } from '../envelope'; -import { getMetricSummaryJsonForSpan } from '../metrics/metric-summary'; import { SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME, SEMANTIC_ATTRIBUTE_PROFILE_ID, @@ -233,7 +232,6 @@ export class SentrySpan implements Span { timestamp: this._endTime, trace_id: this._traceId, origin: this._attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined, - _metrics_summary: getMetricSummaryJsonForSpan(this), profile_id: this._attributes[SEMANTIC_ATTRIBUTE_PROFILE_ID] as string | undefined, exclusive_time: this._attributes[SEMANTIC_ATTRIBUTE_EXCLUSIVE_TIME] as number | undefined, measurements: timedEventsToMeasurements(this._events), @@ -385,7 +383,6 @@ export class SentrySpan implements Span { dynamicSamplingContext: getDynamicSamplingContextFromSpan(this), }), }, - _metrics_summary: getMetricSummaryJsonForSpan(this), ...(source && { transaction_info: { source, diff --git a/packages/core/src/types-hoist/datacategory.ts b/packages/core/src/types-hoist/datacategory.ts index bd1c0b693e4d..da90cc0ca90b 100644 --- a/packages/core/src/types-hoist/datacategory.ts +++ b/packages/core/src/types-hoist/datacategory.ts @@ -26,8 +26,6 @@ export type DataCategory = | 'monitor' // Feedback type event (v2) | 'feedback' - // Metrics sent via the statsd or metrics envelope items - | 'metric_bucket' // Span | 'span' // Unknown data category diff --git a/packages/core/src/types-hoist/envelope.ts b/packages/core/src/types-hoist/envelope.ts index b5e2599942d4..ab7af66f3a01 100644 --- a/packages/core/src/types-hoist/envelope.ts +++ b/packages/core/src/types-hoist/envelope.ts @@ -41,7 +41,6 @@ export type EnvelopeItemType = | 'replay_event' | 'replay_recording' | 'check_in' - | 'statsd' | 'span' | 'raw_security'; @@ -84,7 +83,6 @@ type ReplayRecordingItemHeaders = { type: 'replay_recording'; length: number }; type CheckInItemHeaders = { type: 'check_in' }; type ProfileItemHeaders = { type: 'profile' }; type ProfileChunkItemHeaders = { type: 'profile_chunk' }; -type StatsdItemHeaders = { type: 'statsd'; length: number }; type SpanItemHeaders = { type: 'span' }; type RawSecurityHeaders = { type: 'raw_security'; sentry_release?: string; sentry_environment?: string }; @@ -98,7 +96,6 @@ export type ClientReportItem = BaseEnvelopeItem; type ReplayEventItem = BaseEnvelopeItem; type ReplayRecordingItem = BaseEnvelopeItem; -export type StatsdItem = BaseEnvelopeItem; export type FeedbackItem = BaseEnvelopeItem; export type ProfileItem = BaseEnvelopeItem; export type ProfileChunkItem = BaseEnvelopeItem; @@ -110,7 +107,6 @@ type SessionEnvelopeHeaders = { sent_at: string }; type CheckInEnvelopeHeaders = { trace?: DynamicSamplingContext }; type ClientReportEnvelopeHeaders = BaseEnvelopeHeaders; type ReplayEnvelopeHeaders = BaseEnvelopeHeaders; -type StatsdEnvelopeHeaders = BaseEnvelopeHeaders; type SpanEnvelopeHeaders = BaseEnvelopeHeaders & { trace?: DynamicSamplingContext }; export type EventEnvelope = BaseEnvelope< @@ -121,7 +117,6 @@ export type SessionEnvelope = BaseEnvelope; export type ClientReportEnvelope = BaseEnvelope; export type ReplayEnvelope = [ReplayEnvelopeHeaders, [ReplayEventItem, ReplayRecordingItem]]; export type CheckInEnvelope = BaseEnvelope; -export type StatsdEnvelope = BaseEnvelope; export type SpanEnvelope = BaseEnvelope; export type ProfileChunkEnvelope = BaseEnvelope; export type RawSecurityEnvelope = BaseEnvelope; @@ -133,7 +128,6 @@ export type Envelope = | ProfileChunkEnvelope | ReplayEnvelope | CheckInEnvelope - | StatsdEnvelope | SpanEnvelope | RawSecurityEnvelope; diff --git a/packages/core/src/types-hoist/event.ts b/packages/core/src/types-hoist/event.ts index ff7069d2fdc8..69d6776a54ac 100644 --- a/packages/core/src/types-hoist/event.ts +++ b/packages/core/src/types-hoist/event.ts @@ -13,7 +13,7 @@ import type { PolymorphicRequest } from './polymorphics'; import type { RequestEventData } from './request'; import type { SdkInfo } from './sdkinfo'; import type { SeverityLevel } from './severity'; -import type { MetricSummary, SpanJSON } from './span'; +import type { SpanJSON } from './span'; import type { Thread } from './thread'; import type { TransactionSource } from './transaction'; import type { User } from './user'; @@ -82,7 +82,6 @@ export interface ErrorEvent extends Event { } export interface TransactionEvent extends Event { type: 'transaction'; - _metrics_summary?: Record>; } /** JSDoc */ diff --git a/packages/core/src/types-hoist/index.ts b/packages/core/src/types-hoist/index.ts index f9fbf080153a..82cae72af76d 100644 --- a/packages/core/src/types-hoist/index.ts +++ b/packages/core/src/types-hoist/index.ts @@ -45,8 +45,6 @@ export type { CheckInEnvelope, RawSecurityEnvelope, RawSecurityItem, - StatsdItem, - StatsdEnvelope, ProfileItem, ProfileChunkEnvelope, ProfileChunkItem, @@ -125,7 +123,6 @@ export type { SpanJSON, SpanContextData, TraceFlag, - MetricSummary, } from './span'; export type { SpanStatus } from './spanStatus'; export type { TimedEvent } from './timedEvent'; @@ -173,13 +170,6 @@ export type { export type { BrowserClientReplayOptions, BrowserClientProfilingOptions } from './browseroptions'; export type { CheckIn, MonitorConfig, FinishedCheckIn, InProgressCheckIn, SerializedCheckIn } from './checkin'; -export type { - MetricsAggregator, - MetricBucketItem, - MetricInstance, - MetricData, - Metrics, -} from './metrics'; export type { ParameterizedString } from './parameterize'; export type { ContinuousProfiler, ProfilingIntegration, Profiler } from './profiling'; export type { ViewHierarchyData, ViewHierarchyWindow } from './view-hierarchy'; diff --git a/packages/core/src/types-hoist/metrics.ts b/packages/core/src/types-hoist/metrics.ts deleted file mode 100644 index 474f5b94c207..000000000000 --- a/packages/core/src/types-hoist/metrics.ts +++ /dev/null @@ -1,114 +0,0 @@ -import type { Client } from './client'; -import type { DurationUnit, MeasurementUnit } from './measurement'; -import type { Primitive } from './misc'; - -export interface MetricData { - unit?: MeasurementUnit; - tags?: Record; - timestamp?: number; - client?: Client; -} - -/** - * An abstract definition of the minimum required API - * for a metric instance. - */ -export interface MetricInstance { - /** - * Returns the weight of the metric. - */ - weight: number; - - /** - * Adds a value to a metric. - */ - add(value: number | string): void; - - /** - * Serializes the metric into a statsd format string. - */ - toString(): string; -} - -export interface MetricBucketItem { - metric: MetricInstance; - timestamp: number; - metricType: 'c' | 'g' | 's' | 'd'; - name: string; - unit: MeasurementUnit; - tags: Record; -} - -/** - * A metrics aggregator that aggregates metrics in memory and flushes them periodically. - */ -export interface MetricsAggregator { - /** - * Add a metric to the aggregator. - */ - add( - metricType: 'c' | 'g' | 's' | 'd', - name: string, - value: number | string, - unit?: MeasurementUnit, - tags?: Record, - timestamp?: number, - ): void; - - /** - * Flushes the current metrics to the transport via the transport. - */ - flush(): void; - - /** - * Shuts down metrics aggregator and clears all metrics. - */ - close(): void; - - /** - * Returns a string representation of the aggregator. - */ - toString(): string; -} - -export interface Metrics { - /** - * Adds a value to a counter metric - * - * @experimental This API is experimental and might have breaking changes in the future. - */ - increment(name: string, value?: number, data?: MetricData): void; - - /** - * Adds a value to a distribution metric - * - * @experimental This API is experimental and might have breaking changes in the future. - */ - distribution(name: string, value: number, data?: MetricData): void; - - /** - * Adds a value to a set metric. Value must be a string or integer. - * - * @experimental This API is experimental and might have breaking changes in the future. - */ - set(name: string, value: number | string, data?: MetricData): void; - - /** - * Adds a value to a gauge metric - * - * @experimental This API is experimental and might have breaking changes in the future. - */ - gauge(name: string, value: number, data?: MetricData): void; - - /** - * Adds a timing metric. - * The metric is added as a distribution metric. - * - * You can either directly capture a numeric `value`, or wrap a callback function in `timing`. - * In the latter case, the duration of the callback execution will be captured as a span & a metric. - * - * @experimental This API is experimental and might have breaking changes in the future. - */ - timing(name: string, value: number, unit?: DurationUnit, data?: Omit): void; - timing(name: string, callback: () => T, unit?: DurationUnit, data?: Omit): T; -} diff --git a/packages/core/src/types-hoist/span.ts b/packages/core/src/types-hoist/span.ts index 8e87a115a8b5..c74d00e54f97 100644 --- a/packages/core/src/types-hoist/span.ts +++ b/packages/core/src/types-hoist/span.ts @@ -1,5 +1,4 @@ import type { Measurements } from './measurement'; -import type { Primitive } from './misc'; import type { HrTime } from './opentelemetry'; import type { SpanStatus } from './spanStatus'; import type { TransactionSource } from './transaction'; @@ -31,14 +30,6 @@ export type SpanAttributes = Partial<{ }> & Record; -export type MetricSummary = { - min: number; - max: number; - count: number; - sum: number; - tags?: Record | undefined; -}; - /** This type is aligned with the OpenTelemetry TimeInput type. */ export type SpanTimeInput = HrTime | number | Date; @@ -54,7 +45,6 @@ export interface SpanJSON { timestamp?: number; trace_id: string; origin?: SpanOrigin; - _metrics_summary?: Record>; profile_id?: string; exclusive_time?: number; measurements?: Measurements; diff --git a/packages/core/src/utils-hoist/envelope.ts b/packages/core/src/utils-hoist/envelope.ts index 52fb7e175070..ea2b733f1dc1 100644 --- a/packages/core/src/utils-hoist/envelope.ts +++ b/packages/core/src/utils-hoist/envelope.ts @@ -222,7 +222,6 @@ const ITEM_TYPE_TO_DATA_CATEGORY_MAP: Record = { check_in: 'monitor', feedback: 'feedback', span: 'span', - statsd: 'metric_bucket', raw_security: 'security', }; diff --git a/packages/core/src/utils-hoist/index.ts b/packages/core/src/utils-hoist/index.ts index 6882323782c4..4e1771ffb8fa 100644 --- a/packages/core/src/utils-hoist/index.ts +++ b/packages/core/src/utils-hoist/index.ts @@ -90,8 +90,7 @@ export type { TransactionNamingScheme, } from './requestdata'; -// eslint-disable-next-line deprecation/deprecation -export { severityLevelFromString, validSeverityLevels } from './severity'; +export { severityLevelFromString } from './severity'; export { UNKNOWN_FUNCTION, createStackParser, diff --git a/packages/core/src/utils-hoist/severity.ts b/packages/core/src/utils-hoist/severity.ts index cdf25f6104d0..8b20a03e7ac8 100644 --- a/packages/core/src/utils-hoist/severity.ts +++ b/packages/core/src/utils-hoist/severity.ts @@ -1,10 +1,5 @@ import type { SeverityLevel } from '../types-hoist'; -/** - * @deprecated This variable has been deprecated and will be removed in the next major version. - */ -export const validSeverityLevels = ['fatal', 'error', 'warning', 'log', 'info', 'debug']; - /** * Converts a string-based level into a `SeverityLevel`, normalizing it along the way. * diff --git a/packages/core/src/utils/spanUtils.ts b/packages/core/src/utils/spanUtils.ts index ecfae662b052..c4088fba4942 100644 --- a/packages/core/src/utils/spanUtils.ts +++ b/packages/core/src/utils/spanUtils.ts @@ -1,8 +1,6 @@ import { getAsyncContextStrategy } from '../asyncContext'; import { getMainCarrier } from '../carrier'; import { getCurrentScope } from '../currentScopes'; -import { getMetricSummaryJsonForSpan, updateMetricSummaryOnSpan } from '../metrics/metric-summary'; -import type { MetricType } from '../metrics/types'; import { SEMANTIC_ATTRIBUTE_SENTRY_CUSTOM_SPAN_NAME, SEMANTIC_ATTRIBUTE_SENTRY_OP, @@ -12,8 +10,6 @@ import { import type { SentrySpan } from '../tracing/sentrySpan'; import { SPAN_STATUS_OK, SPAN_STATUS_UNSET } from '../tracing/spanstatus'; import type { - MeasurementUnit, - Primitive, Span, SpanAttributes, SpanJSON, @@ -140,7 +136,6 @@ export function spanToJSON(span: Span): SpanJSON { status: getStatusMessage(status), op: attributes[SEMANTIC_ATTRIBUTE_SENTRY_OP], origin: attributes[SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN] as SpanOrigin | undefined, - _metrics_summary: getMetricSummaryJsonForSpan(span), }); } @@ -281,23 +276,6 @@ export function getActiveSpan(): Span | undefined { return _getSpanForScope(getCurrentScope()); } -/** - * Updates the metric summary on the currently active span - */ -export function updateMetricSummaryOnActiveSpan( - metricType: MetricType, - sanitizedName: string, - value: number, - unit: MeasurementUnit, - tags: Record, - bucketKey: string, -): void { - const span = getActiveSpan(); - if (span) { - updateMetricSummaryOnSpan(span, metricType, sanitizedName, value, unit, tags, bucketKey); - } -} - /** * Logs a warning once if `beforeSendSpan` is used to drop spans. * diff --git a/packages/core/test/lib/metrics/aggregator.test.ts b/packages/core/test/lib/metrics/aggregator.test.ts deleted file mode 100644 index 2a471d12bb04..000000000000 --- a/packages/core/test/lib/metrics/aggregator.test.ts +++ /dev/null @@ -1,138 +0,0 @@ -import { MetricsAggregator } from '../../../src/metrics/aggregator'; -import { MAX_WEIGHT } from '../../../src/metrics/constants'; -import { CounterMetric } from '../../../src/metrics/instance'; -import { serializeMetricBuckets } from '../../../src/metrics/utils'; -import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; - -let testClient: TestClient; - -describe('MetricsAggregator', () => { - const options = getDefaultTestClientOptions({ tracesSampleRate: 0.0 }); - - beforeEach(() => { - jest.useFakeTimers('legacy'); - testClient = new TestClient(options); - }); - - it('adds items to buckets', () => { - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - - const firstValue = aggregator['_buckets'].values().next().value; - expect(firstValue).toEqual({ - metric: expect.any(CounterMetric), - metricType: 'c', - name: 'requests', - tags: {}, - timestamp: expect.any(Number), - unit: 'none', - }); - }); - - it('groups same items together', () => { - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - - const firstValue = aggregator['_buckets'].values().next().value; - expect(firstValue).toEqual({ - metric: expect.any(CounterMetric), - metricType: 'c', - name: 'requests', - tags: {}, - timestamp: expect.any(Number), - unit: 'none', - }); - expect(firstValue.metric._value).toEqual(2); - }); - - it('differentiates based on tag value', () => { - const aggregator = new MetricsAggregator(testClient); - aggregator.add('g', 'cpu', 50); - expect(aggregator['_buckets'].size).toEqual(1); - aggregator.add('g', 'cpu', 55, undefined, { a: 'value' }); - expect(aggregator['_buckets'].size).toEqual(2); - }); - - describe('serializeBuckets', () => { - it('serializes ', () => { - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 8); - aggregator.add('g', 'cpu', 50); - aggregator.add('g', 'cpu', 55); - aggregator.add('g', 'cpu', 52); - aggregator.add('d', 'lcp', 1, 'second', { a: 'value', b: 'anothervalue' }); - aggregator.add('d', 'lcp', 1.2, 'second', { a: 'value', b: 'anothervalue' }); - aggregator.add('s', 'important_people', 'a', 'none', { numericKey: 2 }); - aggregator.add('s', 'important_people', 'b', 'none', { numericKey: 2 }); - - const metricBuckets = Array.from(aggregator['_buckets']).map(([, bucketItem]) => bucketItem); - const serializedBuckets = serializeMetricBuckets(metricBuckets); - - expect(serializedBuckets).toContain('requests@none:8|c|T'); - expect(serializedBuckets).toContain('cpu@none:52:50:55:157:3|g|T'); - expect(serializedBuckets).toContain('lcp@second:1:1.2|d|#a:value,b:anothervalue|T'); - expect(serializedBuckets).toContain('important_people@none:97:98|s|#numericKey:2|T'); - }); - }); - - describe('close', () => { - test('should flush immediately', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - aggregator.close(); - // It should clear the interval. - expect(clearInterval).toHaveBeenCalled(); - expect(capture).toBeCalled(); - expect(capture).toBeCalledTimes(1); - }); - }); - - describe('flush', () => { - test('should flush immediately', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - aggregator.flush(); - expect(capture).toBeCalled(); - expect(capture).toBeCalledTimes(1); - - capture.mockReset(); - aggregator.close(); - // It should clear the interval. - expect(clearInterval).toHaveBeenCalled(); - - // It shouldn't be called since it's been already flushed. - expect(capture).toBeCalledTimes(0); - }); - - test('should not capture if empty', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); - const aggregator = new MetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - aggregator.flush(); - expect(capture).toBeCalledTimes(1); - capture.mockReset(); - aggregator.close(); - expect(capture).toBeCalledTimes(0); - }); - }); - - describe('add', () => { - test('it should respect the max weight and flush if exceeded', () => { - const capture = jest.spyOn(testClient, 'sendEnvelope'); - const aggregator = new MetricsAggregator(testClient); - - for (let i = 0; i < MAX_WEIGHT; i++) { - aggregator.add('c', 'requests', 1); - } - - expect(capture).toBeCalledTimes(1); - aggregator.close(); - }); - }); -}); diff --git a/packages/core/test/lib/metrics/browser-aggregator.test.ts b/packages/core/test/lib/metrics/browser-aggregator.test.ts deleted file mode 100644 index e5ed6b3f8296..000000000000 --- a/packages/core/test/lib/metrics/browser-aggregator.test.ts +++ /dev/null @@ -1,86 +0,0 @@ -import { BrowserMetricsAggregator } from '../../../src/metrics/browser-aggregator'; -import { CounterMetric } from '../../../src/metrics/instance'; -import { serializeMetricBuckets } from '../../../src/metrics/utils'; -import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; - -function _cleanupAggregator(aggregator: BrowserMetricsAggregator): void { - clearInterval(aggregator['_interval']); -} - -describe('BrowserMetricsAggregator', () => { - const options = getDefaultTestClientOptions({ tracesSampleRate: 0.0 }); - const testClient = new TestClient(options); - - it('adds items to buckets', () => { - const aggregator = new BrowserMetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - - const firstValue = aggregator['_buckets'].values().next().value; - expect(firstValue).toEqual({ - metric: expect.any(CounterMetric), - metricType: 'c', - name: 'requests', - tags: {}, - timestamp: expect.any(Number), - unit: 'none', - }); - - _cleanupAggregator(aggregator); - }); - - it('groups same items together', () => { - const aggregator = new BrowserMetricsAggregator(testClient); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - aggregator.add('c', 'requests', 1); - expect(aggregator['_buckets'].size).toEqual(1); - - const firstValue = aggregator['_buckets'].values().next().value; - expect(firstValue).toEqual({ - metric: expect.any(CounterMetric), - metricType: 'c', - name: 'requests', - tags: {}, - timestamp: expect.any(Number), - unit: 'none', - }); - expect(firstValue.metric._value).toEqual(2); - - _cleanupAggregator(aggregator); - }); - - it('differentiates based on tag value', () => { - const aggregator = new BrowserMetricsAggregator(testClient); - aggregator.add('g', 'cpu', 50); - expect(aggregator['_buckets'].size).toEqual(1); - aggregator.add('g', 'cpu', 55, undefined, { a: 'value' }); - expect(aggregator['_buckets'].size).toEqual(2); - - _cleanupAggregator(aggregator); - }); - - describe('serializeBuckets', () => { - it('serializes ', () => { - const aggregator = new BrowserMetricsAggregator(testClient); - aggregator.add('c', 'requests', 8); - aggregator.add('g', 'cpu', 50); - aggregator.add('g', 'cpu', 55); - aggregator.add('g', 'cpu', 52); - aggregator.add('d', 'lcp', 1, 'second', { a: 'value', b: 'anothervalue' }); - aggregator.add('d', 'lcp', 1.2, 'second', { a: 'value', b: 'anothervalue' }); - aggregator.add('s', 'important_people', 'a', 'none', { numericKey: 2 }); - aggregator.add('s', 'important_people', 'b', 'none', { numericKey: 2 }); - - const metricBuckets = Array.from(aggregator['_buckets']).map(([, bucketItem]) => bucketItem); - const serializedBuckets = serializeMetricBuckets(metricBuckets); - - expect(serializedBuckets).toContain('requests@none:8|c|T'); - expect(serializedBuckets).toContain('cpu@none:52:50:55:157:3|g|T'); - expect(serializedBuckets).toContain('lcp@second:1:1.2|d|#a:value,b:anothervalue|T'); - expect(serializedBuckets).toContain('important_people@none:97:98|s|#numericKey:2|T'); - - _cleanupAggregator(aggregator); - }); - }); -}); diff --git a/packages/core/test/lib/metrics/timing.test.ts b/packages/core/test/lib/metrics/timing.test.ts deleted file mode 100644 index 3e48047c9175..000000000000 --- a/packages/core/test/lib/metrics/timing.test.ts +++ /dev/null @@ -1,125 +0,0 @@ -/* eslint-disable deprecation/deprecation */ -import { getCurrentScope, getIsolationScope, setCurrentClient } from '../../../src'; -import { MetricsAggregator } from '../../../src/metrics/aggregator'; -import { metrics as metricsCore } from '../../../src/metrics/exports'; -import { metricsDefault } from '../../../src/metrics/exports-default'; -import { TestClient, getDefaultTestClientOptions } from '../../mocks/client'; - -const PUBLIC_DSN = 'https://username@domain/123'; - -describe('metrics.timing', () => { - let testClient: TestClient; - const options = getDefaultTestClientOptions({ - dsn: PUBLIC_DSN, - tracesSampleRate: 0.0, - }); - - beforeEach(() => { - testClient = new TestClient(options); - setCurrentClient(testClient); - }); - - afterEach(() => { - getCurrentScope().setClient(undefined); - getCurrentScope().clear(); - getIsolationScope().clear(); - }); - - it('works with minimal data', async () => { - const res = metricsDefault.timing('t1', 10); - expect(res).toStrictEqual(undefined); - - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); - - metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); - - expect(sendSpy).toHaveBeenCalledTimes(1); - expect(sendSpy).toHaveBeenCalledWith([ - { sent_at: expect.any(String) }, - [[{ length: expect.any(Number), type: 'statsd' }, expect.stringMatching(/t1@second:10\|d\|T(\d+)/)]], - ]); - }); - - it('allows to define a unit', async () => { - const res = metricsDefault.timing('t1', 10, 'hour'); - expect(res).toStrictEqual(undefined); - - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); - - metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); - - expect(sendSpy).toHaveBeenCalledTimes(1); - expect(sendSpy).toHaveBeenCalledWith([ - { sent_at: expect.any(String) }, - [[{ length: expect.any(Number), type: 'statsd' }, expect.stringMatching(/t1@hour:10\|d\|T(\d+)/)]], - ]); - }); - - it('allows to define data', async () => { - const res = metricsDefault.timing('t1', 10, 'hour', { - tags: { tag1: 'value1', tag2: 'value2' }, - }); - expect(res).toStrictEqual(undefined); - - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); - - metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); - - expect(sendSpy).toHaveBeenCalledTimes(1); - expect(sendSpy).toHaveBeenCalledWith([ - { sent_at: expect.any(String) }, - [ - [ - { length: expect.any(Number), type: 'statsd' }, - expect.stringMatching(/t1@hour:10\|d|#tag1:value1,tag2:value2\|T(\d+)/), - ], - ], - ]); - }); - - it('works with a sync callback', async () => { - const res = metricsDefault.timing('t1', () => { - sleepSync(200); - return 'oho'; - }); - expect(res).toStrictEqual('oho'); - - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); - - metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); - - expect(sendSpy).toHaveBeenCalledTimes(1); - expect(sendSpy).toHaveBeenCalledWith([ - { sent_at: expect.any(String) }, - [[{ length: expect.any(Number), type: 'statsd' }, expect.stringMatching(/t1@second:(0.\d+)\|d\|T(\d+)/)]], - ]); - }); - - it('works with an async callback', async () => { - const res = metricsDefault.timing('t1', async () => { - await new Promise(resolve => setTimeout(resolve, 200)); - return 'oho'; - }); - expect(res).toBeInstanceOf(Promise); - expect(await res).toStrictEqual('oho'); - - const sendSpy = jest.spyOn(testClient.getTransport()!, 'send'); - - metricsCore.getMetricsAggregatorForClient(testClient, MetricsAggregator)!.flush(); - - expect(sendSpy).toHaveBeenCalledTimes(1); - expect(sendSpy).toHaveBeenCalledWith([ - { sent_at: expect.any(String) }, - [[{ length: expect.any(Number), type: 'statsd' }, expect.stringMatching(/t1@second:(0.\d+)\|d\|T(\d+)/)]], - ]); - }); -}); - -function sleepSync(milliseconds: number): void { - const start = Date.now(); - for (let i = 0; i < 1e7; i++) { - if (new Date().getTime() - start > milliseconds) { - break; - } - } -} diff --git a/packages/core/test/lib/metrics/utils.test.ts b/packages/core/test/lib/metrics/utils.test.ts deleted file mode 100644 index e25014715748..000000000000 --- a/packages/core/test/lib/metrics/utils.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { - COUNTER_METRIC_TYPE, - DISTRIBUTION_METRIC_TYPE, - GAUGE_METRIC_TYPE, - SET_METRIC_TYPE, -} from '../../../src/metrics/constants'; -import { getBucketKey, sanitizeTags } from '../../../src/metrics/utils'; - -describe('getBucketKey', () => { - it.each([ - [COUNTER_METRIC_TYPE, 'requests', 'none', {}, 'crequestsnone'], - [GAUGE_METRIC_TYPE, 'cpu', 'none', {}, 'gcpunone'], - [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { a: 'value', b: 'anothervalue' }, 'dlcpseconda,value,b,anothervalue'], - [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { b: 'anothervalue', a: 'value' }, 'dlcpseconda,value,b,anothervalue'], - [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { a: '1', b: '2', c: '3' }, 'dlcpseconda,1,b,2,c,3'], - [DISTRIBUTION_METRIC_TYPE, 'lcp', 'second', { numericKey: '2' }, 'dlcpsecondnumericKey,2'], - [SET_METRIC_TYPE, 'important_org_ids', 'none', { numericKey: '2' }, 'simportant_org_idsnonenumericKey,2'], - ])('should return', (metricType, name, unit, tags, expected) => { - expect(getBucketKey(metricType, name, unit, tags)).toEqual(expected); - }); - - it('should sanitize tags', () => { - const inputTags = { - 'f-oo|bar': '%$foo/', - 'foo$.$.$bar': 'blah{}', - 'foö-bar': 'snöwmän', - route: 'GET /foo', - __bar__: 'this | or , that', - 'foo/': 'hello!\n\r\t\\', - }; - - const outputTags = { - 'f-oobar': '%$foo/', - 'foo..bar': 'blah{}', - 'fo-bar': 'snöwmän', - route: 'GET /foo', - __bar__: 'this \\u{7c} or \\u{2c} that', - 'foo/': 'hello!\\n\\r\\t\\\\', - }; - - expect(sanitizeTags(inputTags)).toEqual(outputTags); - }); -}); diff --git a/packages/core/test/lib/tracing/sentrySpan.test.ts b/packages/core/test/lib/tracing/sentrySpan.test.ts index 2998542453fa..52f116df8349 100644 --- a/packages/core/test/lib/tracing/sentrySpan.test.ts +++ b/packages/core/test/lib/tracing/sentrySpan.test.ts @@ -231,7 +231,6 @@ describe('SentrySpan', () => { expect(captureEventSpy).toHaveBeenCalledTimes(1); expect(captureEventSpy).toHaveBeenCalledWith({ - _metrics_summary: undefined, contexts: { trace: { data: { diff --git a/packages/deno/package.json b/packages/deno/package.json index 851252d0435f..0bd8498ceae9 100644 --- a/packages/deno/package.json +++ b/packages/deno/package.json @@ -28,7 +28,7 @@ }, "devDependencies": { "@rollup/plugin-typescript": "^11.1.5", - "@types/node": "20.8.2", + "@types/node": "^18.19.1", "rollup-plugin-dts": "^6.1.0" }, "scripts": { diff --git a/packages/deno/src/index.ts b/packages/deno/src/index.ts index 72938e767b33..40f43bb0d5c2 100644 --- a/packages/deno/src/index.ts +++ b/packages/deno/src/index.ts @@ -64,8 +64,6 @@ export { startSpanManual, startNewTrace, suppressTracing, - // eslint-disable-next-line deprecation/deprecation - metricsDefault as metrics, inboundFiltersIntegration, linkedErrorsIntegration, functionToStringIntegration, diff --git a/packages/ember/package.json b/packages/ember/package.json index 1547eed88d94..1e111f752d71 100644 --- a/packages/ember/package.json +++ b/packages/ember/package.json @@ -72,7 +72,7 @@ "webpack": "~5.95.0" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "ember": { "edition": "octane" diff --git a/packages/eslint-config-sdk/package.json b/packages/eslint-config-sdk/package.json index 246f51ed6dcf..fc85554ac878 100644 --- a/packages/eslint-config-sdk/package.json +++ b/packages/eslint-config-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/src" diff --git a/packages/eslint-plugin-sdk/package.json b/packages/eslint-plugin-sdk/package.json index 7a6a729fc0cd..402a304747d5 100644 --- a/packages/eslint-plugin-sdk/package.json +++ b/packages/eslint-plugin-sdk/package.json @@ -12,7 +12,7 @@ "sentry" ], "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/src" diff --git a/packages/feedback/package.json b/packages/feedback/package.json index a5e44856378e..ec9451115a27 100644 --- a/packages/feedback/package.json +++ b/packages/feedback/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build/npm" diff --git a/packages/gatsby/package.json b/packages/gatsby/package.json index 2c03fae30f14..3fe9850166dd 100644 --- a/packages/gatsby/package.json +++ b/packages/gatsby/package.json @@ -11,7 +11,7 @@ "gatsby-plugin" ], "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build", diff --git a/packages/google-cloud-serverless/package.json b/packages/google-cloud-serverless/package.json index 52008df49931..236674dc37d3 100644 --- a/packages/google-cloud-serverless/package.json +++ b/packages/google-cloud-serverless/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" @@ -57,7 +57,7 @@ "@google-cloud/common": "^3.4.1", "@google-cloud/functions-framework": "^1.7.1", "@google-cloud/pubsub": "^2.5.0", - "@types/node": "^14.18.0", + "@types/node": "^18.19.1", "google-gax": "^2.9.0", "nock": "^13.5.5" }, diff --git a/packages/google-cloud-serverless/src/index.ts b/packages/google-cloud-serverless/src/index.ts index 24c1f137c5c7..2c04193da8f3 100644 --- a/packages/google-cloud-serverless/src/index.ts +++ b/packages/google-cloud-serverless/src/index.ts @@ -77,8 +77,6 @@ export { continueTrace, getAutoPerformanceIntegrations, cron, - // eslint-disable-next-line deprecation/deprecation - metrics, parameterize, SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, diff --git a/packages/google-cloud-serverless/test/gcpfunction/cloud_event.test.ts b/packages/google-cloud-serverless/test/gcpfunction/cloud_event.test.ts index 941d4d259930..95323881828d 100644 --- a/packages/google-cloud-serverless/test/gcpfunction/cloud_event.test.ts +++ b/packages/google-cloud-serverless/test/gcpfunction/cloud_event.test.ts @@ -44,8 +44,8 @@ describe('wrapCloudEventFunction', () => { function handleCloudEvent(fn: CloudEventFunctionWithCallback): Promise { return new Promise((resolve, reject) => { + // eslint-disable-next-line deprecation/deprecation const d = domain.create(); - // d.on('error', () => res.end()); const context = { type: 'event.type', }; diff --git a/packages/google-cloud-serverless/test/gcpfunction/events.test.ts b/packages/google-cloud-serverless/test/gcpfunction/events.test.ts index 363147409fd2..aa449f5407c9 100644 --- a/packages/google-cloud-serverless/test/gcpfunction/events.test.ts +++ b/packages/google-cloud-serverless/test/gcpfunction/events.test.ts @@ -45,8 +45,8 @@ describe('wrapEventFunction', () => { function handleEvent(fn: EventFunctionWithCallback): Promise { return new Promise((resolve, reject) => { + // eslint-disable-next-line deprecation/deprecation const d = domain.create(); - // d.on('error', () => res.end()); const context = { eventType: 'event.type', resource: 'some.resource', diff --git a/packages/google-cloud-serverless/test/gcpfunction/http.test.ts b/packages/google-cloud-serverless/test/gcpfunction/http.test.ts index 5590add6f618..08d53df50b31 100644 --- a/packages/google-cloud-serverless/test/gcpfunction/http.test.ts +++ b/packages/google-cloud-serverless/test/gcpfunction/http.test.ts @@ -58,6 +58,7 @@ describe('GCPFunction', () => { headers = { ...headers, ...trace_headers }; } return new Promise((resolve, _reject) => { + // eslint-disable-next-line deprecation/deprecation const d = domain.create(); const req = { method: 'POST', diff --git a/packages/integration-shims/package.json b/packages/integration-shims/package.json index 322922a945a0..c5e3c3b4d3f8 100644 --- a/packages/integration-shims/package.json +++ b/packages/integration-shims/package.json @@ -58,7 +58,7 @@ "@sentry/core": "8.45.0" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "volta": { "extends": "../../package.json" diff --git a/packages/integration-shims/src/index.ts b/packages/integration-shims/src/index.ts index 616f9910cf35..510b26ddbb76 100644 --- a/packages/integration-shims/src/index.ts +++ b/packages/integration-shims/src/index.ts @@ -1,4 +1,3 @@ export { feedbackIntegrationShim } from './Feedback'; export { replayIntegrationShim } from './Replay'; export { browserTracingIntegrationShim } from './BrowserTracing'; -export { metricsShim } from './metrics'; diff --git a/packages/integration-shims/src/metrics.ts b/packages/integration-shims/src/metrics.ts deleted file mode 100644 index a8862ee39c03..000000000000 --- a/packages/integration-shims/src/metrics.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { consoleSandbox } from '@sentry/core'; -import type { Metrics } from '@sentry/core'; - -function warn(): void { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn('You are using metrics even though this bundle does not include tracing.'); - }); -} - -export const metricsShim: Metrics = { - increment: warn, - distribution: warn, - set: warn, - gauge: warn, - timing: (_name: unknown, value: number | (() => unknown)) => { - warn(); - if (typeof value === 'function') { - return value(); - } - }, -}; diff --git a/packages/nestjs/README.md b/packages/nestjs/README.md index 1a3ae775b7fd..ae2c35c4c2ab 100644 --- a/packages/nestjs/README.md +++ b/packages/nestjs/README.md @@ -74,7 +74,7 @@ decorator will report all unexpected errors that are received by your global err ```typescript import { Catch, ExceptionFilter } from '@nestjs/common'; -import { WithSentry } from '@sentry/nestjs'; +import { SentryExceptionCaptured } from '@sentry/nestjs'; @Catch() export class YourCatchAllExceptionFilter implements ExceptionFilter { diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index a11de76a0c31..18f83f3b36f4 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" }, "files": [ "/build", diff --git a/packages/nestjs/src/decorators.ts b/packages/nestjs/src/decorators.ts index 89e82588cd7a..42592e62d553 100644 --- a/packages/nestjs/src/decorators.ts +++ b/packages/nestjs/src/decorators.ts @@ -74,10 +74,3 @@ export function SentryExceptionCaptured() { return descriptor; }; } - -/** - * A decorator to wrap user-defined exception filters and add Sentry error reporting. - * - * @deprecated This decorator was renamed and will be removed in a future major version. Use `SentryExceptionCaptured` instead. - */ -export const WithSentry = SentryExceptionCaptured; diff --git a/packages/nestjs/src/index.ts b/packages/nestjs/src/index.ts index dc8815477910..f22ce71ea89d 100644 --- a/packages/nestjs/src/index.ts +++ b/packages/nestjs/src/index.ts @@ -2,12 +2,6 @@ export * from '@sentry/node'; export { nestIntegration } from './integrations/nest'; -export { init, getDefaultIntegrations } from './sdk'; +export { getDefaultIntegrations, init } from './sdk'; -export { - SentryTraced, - SentryCron, - // eslint-disable-next-line deprecation/deprecation - WithSentry, - SentryExceptionCaptured, -} from './decorators'; +export { SentryCron, SentryExceptionCaptured, SentryTraced } from './decorators'; diff --git a/packages/nextjs/package.json b/packages/nextjs/package.json index baafbe149a1d..1d0686747347 100644 --- a/packages/nextjs/package.json +++ b/packages/nextjs/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "main": "build/cjs/index.server.js", "module": "build/esm/index.server.js", @@ -118,7 +118,6 @@ "test": "yarn test:unit", "test:all": "run-s test:unit", "test:unit": "jest", - "test:types": "cd test/types && yarn test", "test:watch": "jest --watch", "vercel:branch": "source vercel/set-up-branch-for-test-app-use.sh", "vercel:project": "source vercel/make-project-use-current-branch.sh", diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index 9fb3bef49e67..d8a29d7d025c 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -340,7 +340,7 @@ export function constructWebpackConfigFunction( if (!isServer && !userSentryOptions.sourcemaps?.deleteSourcemapsAfterUpload) { // eslint-disable-next-line no-console console.warn( - "[@sentry/nextjs] The Sentry SDK has enabled source map generation for your Next.js app. If you don't want to serve Source Maps to your users, either set the `deleteSourceMapsAfterUpload` option to true, or manually delete the source maps after the build. In future Sentry SDK versions `deleteSourceMapsAfterUpload` will default to `true`. If you do not want to generate and upload sourcemaps, set the `sourcemaps.disable` option in `withSentryConfig()`.", + "[@sentry/nextjs] The Sentry SDK has enabled source map generation for your Next.js app. If you don't want to serve Source Maps to your users, either set the `sourcemaps.deleteSourcemapsAfterUpload` option to true, or manually delete the source maps after the build. In future Sentry SDK versions `sourcemaps.deleteSourcemapsAfterUpload` will default to `true`. If you do not want to generate and upload sourcemaps, set the `sourcemaps.disable` option in `withSentryConfig()`.", ); } diff --git a/packages/nextjs/src/index.types.ts b/packages/nextjs/src/index.types.ts index 1b965828116f..1c2b17d3a9f9 100644 --- a/packages/nextjs/src/index.types.ts +++ b/packages/nextjs/src/index.types.ts @@ -36,9 +36,6 @@ export declare const createReduxEnhancer: typeof clientSdk.createReduxEnhancer; export declare const showReportDialog: typeof clientSdk.showReportDialog; export declare const withErrorBoundary: typeof clientSdk.withErrorBoundary; -// eslint-disable-next-line deprecation/deprecation -export declare const metrics: typeof clientSdk.metrics & typeof serverSdk.metrics; - export { withSentryConfig } from './config'; /** diff --git a/packages/nextjs/test/types/.gitignore b/packages/nextjs/test/types/.gitignore deleted file mode 100644 index 23d67fc10447..000000000000 --- a/packages/nextjs/test/types/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -yarn.lock diff --git a/packages/nextjs/test/types/next.config.ts b/packages/nextjs/test/types/next.config.ts deleted file mode 100644 index 1039c99162b2..000000000000 --- a/packages/nextjs/test/types/next.config.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type { NextConfig } from 'next'; - -import { withSentryConfig } from '../../src/config/withSentryConfig'; - -const config: NextConfig = { - webpack: config => ({ - ...config, - module: { - ...config.module, - rules: [...config.module.rules], - }, - }), -}; - -module.exports = withSentryConfig(config); diff --git a/packages/nextjs/test/types/package.json b/packages/nextjs/test/types/package.json deleted file mode 100644 index 86f74bfe060a..000000000000 --- a/packages/nextjs/test/types/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "This is used to install the nextjs v12 so we can test against those types", - "scripts": { - "test": "ts-node test.ts" - }, - "dependencies": { - "next": "13.2.0" - } -} diff --git a/packages/nextjs/test/types/test.ts b/packages/nextjs/test/types/test.ts deleted file mode 100644 index f9f45d29f29b..000000000000 --- a/packages/nextjs/test/types/test.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { execSync } from 'child_process'; -/* eslint-disable no-console */ -import { parseSemver } from '@sentry/core'; - -const NODE_VERSION = parseSemver(process.versions.node); - -if (NODE_VERSION.major && NODE_VERSION.major >= 12) { - console.log('Installing next@v12...'); - execSync('yarn install', { stdio: 'inherit' }); - console.log('Testing some types...'); - execSync('tsc --noEmit --project tsconfig.json', { stdio: 'inherit' }); -} diff --git a/packages/nextjs/test/types/tsconfig.json b/packages/nextjs/test/types/tsconfig.json deleted file mode 100644 index adedc2fafa6c..000000000000 --- a/packages/nextjs/test/types/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../tsconfig.json", - "include": [ - "./**/*" - ] -} diff --git a/packages/nitro-utils/package.json b/packages/nitro-utils/package.json index 06ec390ef87f..2f7061aa1479 100644 --- a/packages/nitro-utils/package.json +++ b/packages/nitro-utils/package.json @@ -8,7 +8,7 @@ "license": "MIT", "private": true, "engines": { - "node": ">=16.20" + "node": ">=18.19.1" }, "files": [ "/build" diff --git a/packages/node/package.json b/packages/node/package.json index 2724bb85a7ad..ca564b0e8fb7 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" @@ -101,7 +101,7 @@ "import-in-the-middle": "^1.11.2" }, "devDependencies": { - "@types/node": "^14.18.0" + "@types/node": "^18.19.1" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 66fa8cd27e4a..b4c556c39f81 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -117,8 +117,6 @@ export { dedupeIntegration, extraErrorDataIntegration, rewriteFramesIntegration, - // eslint-disable-next-line deprecation/deprecation - metricsDefault as metrics, startSession, captureSession, endSession, diff --git a/packages/node/src/integrations/tracing/prisma.ts b/packages/node/src/integrations/tracing/prisma.ts index a42d41a6b5ec..010493fff77d 100644 --- a/packages/node/src/integrations/tracing/prisma.ts +++ b/packages/node/src/integrations/tracing/prisma.ts @@ -29,7 +29,9 @@ const _prismaIntegration = (() => { span.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, 'auto.db.otel.prisma'); } - if (spanJSON.description === 'prisma:engine:db_query') { + // In Prisma v5.22+, the `db.system` attribute is automatically set + // On older versions, this is missing, so we add it here + if (spanJSON.description === 'prisma:engine:db_query' && !spanJSON.data['db.system']) { span.setAttribute('db.system', 'prisma'); } }); diff --git a/packages/node/src/proxy/parse-proxy-response.ts b/packages/node/src/proxy/parse-proxy-response.ts index a2c05b1dbe2c..afad0d2435f4 100644 --- a/packages/node/src/proxy/parse-proxy-response.ts +++ b/packages/node/src/proxy/parse-proxy-response.ts @@ -89,7 +89,7 @@ export function parseProxyResponse(socket: Readable): Promise<{ connect: Connect return; } - const headerParts = buffered.slice(0, endOfHeaders).toString('ascii').split('\r\n'); + const headerParts = buffered.subarray(0, endOfHeaders).toString('ascii').split('\r\n'); const firstLine = headerParts.shift(); if (!firstLine) { socket.destroy(); diff --git a/packages/nuxt/package.json b/packages/nuxt/package.json index 86ce75ba76f8..bee5e78f7582 100644 --- a/packages/nuxt/package.json +++ b/packages/nuxt/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.19.1" }, "files": [ "/build" diff --git a/packages/nuxt/src/index.types.ts b/packages/nuxt/src/index.types.ts index fd4bd00856be..e22175f67b43 100644 --- a/packages/nuxt/src/index.types.ts +++ b/packages/nuxt/src/index.types.ts @@ -15,5 +15,3 @@ export declare const contextLinesIntegration: typeof clientSdk.contextLinesInteg export declare const getDefaultIntegrations: (options: Options) => Integration[]; export declare const defaultStackParser: StackParser; export declare const continueTrace: typeof clientSdk.continueTrace; -// eslint-disable-next-line deprecation/deprecation -export declare const metrics: typeof clientSdk.metrics & typeof serverSdk.metrics; diff --git a/packages/opentelemetry/package.json b/packages/opentelemetry/package.json index e342a8d34be8..db008ad65f62 100644 --- a/packages/opentelemetry/package.json +++ b/packages/opentelemetry/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/opentelemetry/src/spanExporter.ts b/packages/opentelemetry/src/spanExporter.ts index bff6518eb27d..c6a838a5574f 100644 --- a/packages/opentelemetry/src/spanExporter.ts +++ b/packages/opentelemetry/src/spanExporter.ts @@ -21,7 +21,6 @@ import { dropUndefinedKeys, getCapturedScopesOnSpan, getDynamicSamplingContextFromSpan, - getMetricSummaryJsonForSpan, getStatusMessage, logger, spanTimeInputToSeconds, @@ -298,7 +297,6 @@ export function createTransactionForOtelSpan(span: ReadableSpan): TransactionEve source, }, }), - _metrics_summary: getMetricSummaryJsonForSpan(span as unknown as Span), }); return transactionEvent; @@ -348,7 +346,6 @@ function createAndFinishSpanForOtelSpan(node: SpanNode, spans: SpanJSON[], sentS status: getStatusMessage(status), // As per protocol, span status is allowed to be undefined op, origin, - _metrics_summary: getMetricSummaryJsonForSpan(span as unknown as Span), measurements: timedEventsToMeasurements(span.events), }); diff --git a/packages/profiling-node/README.md b/packages/profiling-node/README.md index 890022ae2e88..e96bc41eb569 100644 --- a/packages/profiling-node/README.md +++ b/packages/profiling-node/README.md @@ -12,8 +12,7 @@ ## Installation -Profiling works as an extension of tracing so you will need both @sentry/node and @sentry/profiling-node installed. The -minimum required major version of @sentry/node that supports profiling is 7.x. +Profiling works as an extension of tracing so you will need both @sentry/node and @sentry/profiling-node installed. ```bash # Using yarn @@ -84,7 +83,7 @@ After the binaries are built, you should see them inside the profiling-node/lib ### Prebuilt binaries -We currently ship prebuilt binaries for a few of the most common platforms and node versions (v16-22). +We currently ship prebuilt binaries for a few of the most common platforms and node versions (v18-22). - macOS x64 - Linux ARM64 (musl) diff --git a/packages/profiling-node/package.json b/packages/profiling-node/package.json index 19ecb062875e..80a35a718838 100644 --- a/packages/profiling-node/package.json +++ b/packages/profiling-node/package.json @@ -32,7 +32,7 @@ "sentry-prune-profiler-binaries": "scripts/prune-profiler-binaries.js" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "publishConfig": { "access": "public" @@ -81,7 +81,7 @@ "node-abi": "^3.61.0" }, "devDependencies": { - "@types/node": "16.18.70", + "@types/node": "^18.19.1", "@types/node-abi": "^3.0.3", "clang-format": "^1.8.0", "cross-env": "^7.0.3", diff --git a/packages/profiling-node/src/utils.ts b/packages/profiling-node/src/utils.ts index 1c0828a5468c..78844af5fa8e 100644 --- a/packages/profiling-node/src/utils.ts +++ b/packages/profiling-node/src/utils.ts @@ -37,16 +37,12 @@ export const PROFILER_THREAD_NAME = isMainThread ? 'main' : 'worker'; const FORMAT_VERSION = '1'; const CONTINUOUS_FORMAT_VERSION = '2'; -// Os machine was backported to 16.18, but this was not reflected in the types -// @ts-expect-error ignore missing -const machine = typeof os.machine === 'function' ? os.machine() : os.arch(); - // Machine properties (eval only once) const PLATFORM = os.platform(); const RELEASE = os.release(); const VERSION = os.version(); const TYPE = os.type(); -const MODEL = machine; +const MODEL = os.machine(); const ARCH = os.arch(); /** diff --git a/packages/react/package.json b/packages/react/package.json index d14ad2f112a8..81596144ae79 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/remix/package.json b/packages/remix/package.json index 9967c77676bc..05d9c5ef157a 100644 --- a/packages/remix/package.json +++ b/packages/remix/package.json @@ -10,7 +10,7 @@ "sentry-upload-sourcemaps": "scripts/sentry-upload-sourcemaps.js" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build", diff --git a/packages/remix/src/index.server.ts b/packages/remix/src/index.server.ts index 7c4d1460edd6..109e76d7053f 100644 --- a/packages/remix/src/index.server.ts +++ b/packages/remix/src/index.server.ts @@ -77,8 +77,6 @@ export { linkedErrorsIntegration, localVariablesIntegration, makeNodeTransport, - // eslint-disable-next-line deprecation/deprecation - metrics, modulesIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/remix/src/index.types.ts b/packages/remix/src/index.types.ts index cfba5f67e781..77ad6e59f998 100644 --- a/packages/remix/src/index.types.ts +++ b/packages/remix/src/index.types.ts @@ -38,6 +38,3 @@ export declare const continueTrace: typeof clientSdk.continueTrace; export const close = runtime === 'client' ? clientSdk.close : serverSdk.close; export const flush = runtime === 'client' ? clientSdk.flush : serverSdk.flush; export const lastEventId = runtime === 'client' ? clientSdk.lastEventId : serverSdk.lastEventId; - -// eslint-disable-next-line deprecation/deprecation -export declare const metrics: typeof clientSdk.metrics & typeof serverSdk.metrics; diff --git a/packages/remix/test/integration/package.json b/packages/remix/test/integration/package.json index b00f17b330f9..82c46d519f63 100644 --- a/packages/remix/test/integration/package.json +++ b/packages/remix/test/integration/package.json @@ -40,6 +40,6 @@ "**/path-scurry/lru-cache": "10.2.0" }, "engines": { - "node": ">=14.18" + "node": ">=18" } } diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index 4faeb7db1ef7..3f0367c201e0 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -72,7 +72,7 @@ "@sentry/core": "8.45.0" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "volta": { "extends": "../../package.json" diff --git a/packages/replay-internal/package.json b/packages/replay-internal/package.json index 4267723b8b67..9c24ba5f5511 100644 --- a/packages/replay-internal/package.json +++ b/packages/replay-internal/package.json @@ -80,7 +80,7 @@ "@sentry/core": "8.45.0" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "volta": { "extends": "../../package.json" diff --git a/packages/replay-internal/src/util/getPrivacyOptions.ts b/packages/replay-internal/src/util/getPrivacyOptions.ts index ba35ec21476d..a5aa3d392632 100644 --- a/packages/replay-internal/src/util/getPrivacyOptions.ts +++ b/packages/replay-internal/src/util/getPrivacyOptions.ts @@ -25,7 +25,7 @@ function getOption(selectors: string[], defaultSelectors: string[]): string { * Returns privacy related configuration for use in rrweb */ export function getPrivacyOptions({ mask, unmask, block, unblock, ignore }: GetPrivacyOptions): GetPrivacyReturn { - const defaultBlockedElements = ['base[href="/"]']; + const defaultBlockedElements = ['base', 'iframe[srcdoc]:not([src])']; const maskSelector = getOption(mask, ['.sentry-mask', '[data-sentry-mask]']); const unmaskSelector = getOption(unmask, []); diff --git a/packages/replay-internal/test/integration/integrationSettings.test.ts b/packages/replay-internal/test/integration/integrationSettings.test.ts index 62dc2a4a6588..8f7f39fdcf1a 100644 --- a/packages/replay-internal/test/integration/integrationSettings.test.ts +++ b/packages/replay-internal/test/integration/integrationSettings.test.ts @@ -17,7 +17,9 @@ describe('Integration | integrationSettings', () => { it('sets the correct configuration when `blockAllMedia` is disabled', async () => { const { replay } = await mockSdk({ replayOptions: { blockAllMedia: false } }); - expect(replay['_recordingOptions'].blockSelector).toBe('.sentry-block,[data-sentry-block],base[href="/"]'); + expect(replay['_recordingOptions'].blockSelector).toBe( + '.sentry-block,[data-sentry-block],base,iframe[srcdoc]:not([src])', + ); }); }); diff --git a/packages/replay-internal/test/integration/rrweb.test.ts b/packages/replay-internal/test/integration/rrweb.test.ts index 4327ddb21de1..cd3fbcd095be 100644 --- a/packages/replay-internal/test/integration/rrweb.test.ts +++ b/packages/replay-internal/test/integration/rrweb.test.ts @@ -23,7 +23,7 @@ describe('Integration | rrweb', () => { }); expect(mockRecord.mock.calls[0]?.[0]).toMatchInlineSnapshot(` { - "blockSelector": ".sentry-block,[data-sentry-block],base[href="/"],img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]", + "blockSelector": ".sentry-block,[data-sentry-block],base,iframe[srcdoc]:not([src]),img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]", "collectFonts": true, "emit": [Function], "errorHandler": [Function], @@ -62,7 +62,7 @@ describe('Integration | rrweb', () => { expect(mockRecord.mock.calls[0]?.[0]).toMatchInlineSnapshot(` { - "blockSelector": ".sentry-block,[data-sentry-block],base[href="/"],img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]", + "blockSelector": ".sentry-block,[data-sentry-block],base,iframe[srcdoc]:not([src]),img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]", "checkoutEveryNms": 360000, "collectFonts": true, "emit": [Function], diff --git a/packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts b/packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts index 8595ca6aa1c4..3123e3efaa7c 100644 --- a/packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts +++ b/packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts @@ -21,7 +21,7 @@ describe('Unit | util | getPrivacyOptions', () => { }), ).toMatchInlineSnapshot(` { - "blockSelector": ".custom-block,.sentry-block,[data-sentry-block],base[href="/"]", + "blockSelector": ".custom-block,.sentry-block,[data-sentry-block],base,iframe[srcdoc]:not([src])", "ignoreSelector": ".custom-ignore,.sentry-ignore,[data-sentry-ignore],input[type="file"]", "maskTextSelector": ".custom-mask,.sentry-mask,[data-sentry-mask]", "unblockSelector": ".custom-unblock", diff --git a/packages/replay-worker/package.json b/packages/replay-worker/package.json index 7a1596319e4f..43ea5e9c0d1e 100644 --- a/packages/replay-worker/package.json +++ b/packages/replay-worker/package.json @@ -49,7 +49,7 @@ "fflate": "0.8.1" }, "engines": { - "node": ">=14.18" + "node": ">=18" }, "volta": { "extends": "../../package.json" diff --git a/packages/solid/package.json b/packages/solid/package.json index f718a1374a11..266e1b197b52 100644 --- a/packages/solid/package.json +++ b/packages/solid/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build", diff --git a/packages/solidstart/package.json b/packages/solidstart/package.json index dba27d321153..e64c0d5d4b20 100644 --- a/packages/solidstart/package.json +++ b/packages/solidstart/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18.19.1" }, "files": [ "/build", diff --git a/packages/solidstart/src/index.types.ts b/packages/solidstart/src/index.types.ts index 85b712281f38..a204201081dd 100644 --- a/packages/solidstart/src/index.types.ts +++ b/packages/solidstart/src/index.types.ts @@ -26,6 +26,3 @@ export declare function flush(timeout?: number | undefined): PromiseLike=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/sveltekit/package.json b/packages/sveltekit/package.json index 7ae146015a74..4961d2727696 100644 --- a/packages/sveltekit/package.json +++ b/packages/sveltekit/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/sveltekit/src/index.types.ts b/packages/sveltekit/src/index.types.ts index 95cac7b9318b..5dc73ae4ed68 100644 --- a/packages/sveltekit/src/index.types.ts +++ b/packages/sveltekit/src/index.types.ts @@ -52,7 +52,4 @@ export declare function lastEventId(): string | undefined; export declare const continueTrace: typeof clientSdk.continueTrace; -// eslint-disable-next-line deprecation/deprecation -export declare const metrics: typeof clientSdk.metrics & typeof serverSdk.metrics; - export declare function trackComponent(options: clientSdk.TrackingOptions): ReturnType; diff --git a/packages/sveltekit/src/server/index.ts b/packages/sveltekit/src/server/index.ts index 3e02465ce250..ff31b715768f 100644 --- a/packages/sveltekit/src/server/index.ts +++ b/packages/sveltekit/src/server/index.ts @@ -71,8 +71,6 @@ export { linkedErrorsIntegration, localVariablesIntegration, makeNodeTransport, - // eslint-disable-next-line deprecation/deprecation - metrics, modulesIntegration, mongoIntegration, mongooseIntegration, diff --git a/packages/types/package.json b/packages/types/package.json index 26927c6882b9..5be24f954f1b 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 565589bc0fbb..5dc7a916c9d7 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -83,12 +83,6 @@ import type { MeasurementUnit as MeasurementUnit_imported, Measurements as Measurements_imported, Mechanism as Mechanism_imported, - MetricBucketItem as MetricBucketItem_imported, - MetricData as MetricData_imported, - MetricInstance as MetricInstance_imported, - MetricSummary as MetricSummary_imported, - Metrics as Metrics_imported, - MetricsAggregator as MetricsAggregator_imported, MissingInstrumentationContext as MissingInstrumentationContext_imported, MonitorConfig as MonitorConfig_imported, NoneUnit as NoneUnit_imported, @@ -158,8 +152,6 @@ import type { StackParser as StackParser_imported, Stacktrace as Stacktrace_imported, StartSpanOptions as StartSpanOptions_imported, - StatsdEnvelope as StatsdEnvelope_imported, - StatsdItem as StatsdItem_imported, Thread as Thread_imported, ThreadCpuFrame as ThreadCpuFrame_imported, ThreadCpuProfile as ThreadCpuProfile_imported, @@ -282,10 +274,6 @@ export type CheckInItem = CheckInItem_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type CheckInEnvelope = CheckInEnvelope_imported; /** @deprecated This type has been moved to `@sentry/core`. */ -export type StatsdItem = StatsdItem_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ -export type StatsdEnvelope = StatsdEnvelope_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ export type ProfileItem = ProfileItem_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type ProfileChunkEnvelope = ProfileChunkEnvelope_imported; @@ -454,8 +442,6 @@ export type SpanContextData = SpanContextData_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type TraceFlag = TraceFlag_imported; /** @deprecated This type has been moved to `@sentry/core`. */ -export type MetricSummary = MetricSummary_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ export type SpanStatus = SpanStatus_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type TimedEvent = TimedEvent_imported; @@ -555,16 +541,6 @@ export type InProgressCheckIn = InProgressCheckIn_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type SerializedCheckIn = SerializedCheckIn_imported; /** @deprecated This type has been moved to `@sentry/core`. */ -export type MetricsAggregator = MetricsAggregator_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ -export type MetricBucketItem = MetricBucketItem_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ -export type MetricInstance = MetricInstance_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ -export type MetricData = MetricData_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ -export type Metrics = Metrics_imported; -/** @deprecated This type has been moved to `@sentry/core`. */ export type ParameterizedString = ParameterizedString_imported; /** @deprecated This type has been moved to `@sentry/core`. */ export type ContinuousProfiler = ContinuousProfiler_imported; diff --git a/packages/utils/package.json b/packages/utils/package.json index b35f0087434b..c8e04a5dac75 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/utils/src/index.ts b/packages/utils/src/index.ts index d227c9af5008..f730b41b30fa 100644 --- a/packages/utils/src/index.ts +++ b/packages/utils/src/index.ts @@ -155,7 +155,6 @@ import { updateRateLimits as updateRateLimits_imported, urlEncode as urlEncode_imported, uuid4 as uuid4_imported, - validSeverityLevels as validSeverityLevels_imported, vercelWaitUntil as vercelWaitUntil_imported, watchdogTimer as watchdogTimer_imported, winterCGHeadersToDict as winterCGHeadersToDict_imported, @@ -340,10 +339,6 @@ export const winterCGRequestToRequestData = winterCGRequestToRequestData_importe /** @deprecated Import from `@sentry/core` instead. */ export const severityLevelFromString = severityLevelFromString_imported; -/** @deprecated Import from `@sentry/core` instead. */ -// eslint-disable-next-line deprecation/deprecation -export const validSeverityLevels = validSeverityLevels_imported; - /** @deprecated Import from `@sentry/core` instead. */ export const UNKNOWN_FUNCTION = UNKNOWN_FUNCTION_imported; diff --git a/packages/vercel-edge/package.json b/packages/vercel-edge/package.json index 4e7f81e055af..90fc7cd39534 100644 --- a/packages/vercel-edge/package.json +++ b/packages/vercel-edge/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/vercel-edge/src/index.ts b/packages/vercel-edge/src/index.ts index 2301d620bb05..0820a4590c70 100644 --- a/packages/vercel-edge/src/index.ts +++ b/packages/vercel-edge/src/index.ts @@ -67,8 +67,6 @@ export { withActiveSpan, getSpanDescendants, continueTrace, - // eslint-disable-next-line deprecation/deprecation - metrics, functionToStringIntegration, inboundFiltersIntegration, linkedErrorsIntegration, diff --git a/packages/vercel-edge/src/vendored/async-local-storage-context-manager.ts b/packages/vercel-edge/src/vendored/async-local-storage-context-manager.ts index 67828f4c852e..8d8a1e6dd171 100644 --- a/packages/vercel-edge/src/vendored/async-local-storage-context-manager.ts +++ b/packages/vercel-edge/src/vendored/async-local-storage-context-manager.ts @@ -52,7 +52,7 @@ export class AsyncLocalStorageContextManager extends AbstractAsyncHooksContextMa getStore() { return undefined; }, - run(_store, callback, ...args) { + run(_store: unknown, callback: () => Context, ...args: unknown[]) { return callback.apply(this, args); }, disable() { diff --git a/packages/vue/package.json b/packages/vue/package.json index 167352a6289b..bf2256e30e11 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build" diff --git a/packages/wasm/package.json b/packages/wasm/package.json index a45a87130c7c..ed871a604375 100644 --- a/packages/wasm/package.json +++ b/packages/wasm/package.json @@ -7,7 +7,7 @@ "author": "Sentry", "license": "MIT", "engines": { - "node": ">=14.18" + "node": ">=18" }, "files": [ "/build/npm" diff --git a/scripts/ci-unit-tests.ts b/scripts/ci-unit-tests.ts index 08459e9eabba..85f852052bac 100644 --- a/scripts/ci-unit-tests.ts +++ b/scripts/ci-unit-tests.ts @@ -2,16 +2,7 @@ import * as childProcess from 'child_process'; import * as fs from 'fs'; import * as path from 'path'; -type NodeVersion = '14' | '16' | '18' | '20' | '21'; - -interface VersionConfig { - ignoredPackages: Array<`@${'sentry' | 'sentry-internal'}/${string}`>; -} - const UNIT_TEST_ENV = process.env.UNIT_TEST_ENV as 'node' | 'browser' | undefined; - -const CURRENT_NODE_VERSION = process.version.replace('v', '').split('.')[0] as NodeVersion; - const RUN_AFFECTED = process.argv.includes('--affected'); // These packages are tested separately in CI, so no need to run them here @@ -35,35 +26,6 @@ const BROWSER_TEST_PACKAGES = [ '@sentry/wasm', ]; -// These are Node-version specific tests that need to be skipped because of support -const SKIP_TEST_PACKAGES: Record = { - '14': { - ignoredPackages: [ - '@sentry/cloudflare', - '@sentry/solidstart', - '@sentry/sveltekit', - '@sentry/vercel-edge', - '@sentry/astro', - '@sentry/nuxt', - '@sentry/nestjs', - '@sentry-internal/eslint-plugin-sdk', - '@sentry-internal/nitro-utils', - ], - }, - '16': { - ignoredPackages: ['@sentry/cloudflare', '@sentry/vercel-edge', '@sentry/astro', '@sentry/solidstart'], - }, - '18': { - ignoredPackages: [], - }, - '20': { - ignoredPackages: [], - }, - '21': { - ignoredPackages: [], - }, -}; - function getAllPackages(): string[] { const { workspaces }: { workspaces: string[] } = JSON.parse( fs.readFileSync(path.join(process.cwd(), 'package.json'), 'utf-8'), @@ -96,11 +58,6 @@ function runTests(): void { BROWSER_TEST_PACKAGES.forEach(pkg => ignores.add(pkg)); } - const versionConfig = SKIP_TEST_PACKAGES[CURRENT_NODE_VERSION]; - if (versionConfig) { - versionConfig.ignoredPackages.forEach(dep => ignores.add(dep)); - } - if (RUN_AFFECTED) { runAffectedTests(ignores); } else { diff --git a/yarn.lock b/yarn.lock index ea225a675006..c6867bdf6f75 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10085,7 +10085,17 @@ dependencies: "@types/unist" "*" -"@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8", "@types/history@*": +"@types/history-4@npm:@types/history@4.7.8": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + +"@types/history-5@npm:@types/history@4.7.8": + version "4.7.8" + resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" + integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== + +"@types/history@*": version "4.7.8" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== @@ -10294,36 +10304,26 @@ "@types/node" "*" "@types/node@*", "@types/node@>=10.0.0", "@types/node@>=12.12.47", "@types/node@>=13.7.0", "@types/node@>=18": - version "22.9.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-22.9.0.tgz#b7f16e5c3384788542c72dc3d561a7ceae2c0365" - integrity sha512-vuyHg81vvWA1Z1ELfvLko2c8f34gyA0zaic0+Rllc5lbCnbSyuvb2Oxpm6TAUAC/2xZN3QGqxBNggD1nNR2AfQ== + version "22.10.2" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.10.2.tgz#a485426e6d1fdafc7b0d4c7b24e2c78182ddabb9" + integrity sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ== dependencies: - undici-types "~6.19.8" - -"@types/node@16.18.70": - version "16.18.70" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.18.70.tgz#d4c819be1e9f8b69a794d6f2fd929d9ff76f6d4b" - integrity sha512-8eIk20G5VVVQNZNouHjLA2b8utE2NvGybLjMaF4lyhA9uhGwnmXF8o+icdXKGSQSNANJewXva/sFUoZLwAaYAg== - -"@types/node@20.8.2": - version "20.8.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.8.2.tgz#d76fb80d87d0d8abfe334fc6d292e83e5524efc4" - integrity sha512-Vvycsc9FQdwhxE3y3DzeIxuEJbWGDsnrxvMADzTDF/lcdR9/K+AQIeAghTQsHtotg/q0j3WEOYS/jQgSdWue3w== + undici-types "~6.20.0" "@types/node@^10.1.0": version "10.17.60" resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.60.tgz#35f3d6213daed95da7f0f73e75bcc6980e90597b" integrity sha512-F0KIgDJfy2nA3zMLmWGKxcH2ZVEtCZXHHdOQs2gSaQ27+lNeEfGxzkIw90aXswATX7AZ33tahPbzy6KAfUreVw== -"@types/node@^14.18.0": +"@types/node@^14.8.0": version "14.18.63" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.18.63.tgz#1788fa8da838dbb5f9ea994b834278205db6ca2b" integrity sha512-fAtCfv4jJg+ExtXhvCkCqUKZ+4ok/JQk01qDKhL5BDDoS3AxKXhV5/MAVUZyQnSEd2GT92fkgZl0pz0Q0AzcIQ== -"@types/node@^18.0.0": - version "18.19.64" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.64.tgz#122897fb79f2a9ec9c979bded01c11461b2b1478" - integrity sha512-955mDqvO2vFf/oL7V3WiUtiz+BugyX8uVbaT2H8oj3+8dRyH2FLiNdowe7eNqRM7IOIZvzDH76EoAT+gwm6aIQ== +"@types/node@^18.19.1": + version "18.19.68" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.68.tgz#f4f10d9927a7eaf3568c46a6d739cc0967ccb701" + integrity sha512-QGtpFH1vB99ZmTa63K4/FU8twThj4fuVSBkGddTp7uIL/cuoLWIUSL2RcOaigBhfR+hg5pgGkBnkoOxrTVBMKw== dependencies: undici-types "~5.26.4" @@ -10412,7 +10412,15 @@ "@types/history" "^3" "@types/react" "*" -"@types/react-router-4@npm:@types/react-router@5.1.14", "@types/react-router-5@npm:@types/react-router@5.1.14": +"@types/react-router-4@npm:@types/react-router@5.1.14": + version "5.1.14" + resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" + integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== + dependencies: + "@types/history" "*" + "@types/react" "*" + +"@types/react-router-5@npm:@types/react-router@5.1.14": version "5.1.14" resolved "https://registry.yarnpkg.com/@types/react-router/-/react-router-5.1.14.tgz#e0442f4eb4c446541ad7435d44a97f8fe6df40da" integrity sha512-LAJpqYUaCTMT2anZheoidiIymt8MuX286zoVFPM3DVb23aQBH0mAkFvzpd4LKqiolV8bBtZWT5Qp7hClCNDENw== @@ -31246,7 +31254,16 @@ string-template@~0.2.1: resolved "https://registry.yarnpkg.com/string-template/-/string-template-0.2.1.tgz#42932e598a352d01fc22ec3367d9d84eec6c9add" integrity sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0= -"string-width-cjs@npm:string-width@^4.2.0", string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@4.2.3, string-width@^4.2.0, string-width@^4.2.2, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -31358,7 +31375,14 @@ stringify-object@^3.2.1: is-obj "^1.0.1" is-regexp "^1.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@6.0.1, strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -32742,10 +32766,10 @@ undici-types@~5.26.4: resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -undici-types@~6.19.8: - version "6.19.8" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" - integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== +undici-types@~6.20.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.20.0.tgz#8171bf22c1f588d1554d55bf204bc624af388433" + integrity sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg== undici@^5.25.4: version "5.28.3" @@ -34387,7 +34411,16 @@ wrangler@^3.67.1: optionalDependencies: fsevents "~2.3.2" -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@7.0.0, wrap-ansi@^7.0.0: +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrap-ansi@7.0.0, wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==