From b6cf7b0cabc27a84e962f0a1e408465cc87fd961 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 5 Aug 2024 13:20:28 +0200 Subject: [PATCH 01/11] ci: Cache playwright separately (#13226) We used to include the playwright binaries in the general dependency cache, which inflated this for no reason. Now, this is not included there anymore. Additionally, I extracted the code to install & cache playwright into a composite action, making it easier to reuse it. --- .github/actions/install-playwright/action.yml | 28 +++++++++ .github/workflows/build.yml | 60 ++++++------------- .github/workflows/flaky-test-detector.yml | 22 +------ 3 files changed, 49 insertions(+), 61 deletions(-) create mode 100644 .github/actions/install-playwright/action.yml diff --git a/.github/actions/install-playwright/action.yml b/.github/actions/install-playwright/action.yml new file mode 100644 index 000000000000..29ecbcfbd2d1 --- /dev/null +++ b/.github/actions/install-playwright/action.yml @@ -0,0 +1,28 @@ +name: "Install Playwright dependencies" +description: "Installs Playwright dependencies and caches them." + +runs: + using: "composite" + steps: + - name: Get Playwright version + id: playwright-version + run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT + shell: bash + + - name: Cache playwright binaries + uses: actions/cache@v4 + id: playwright-cache + with: + path: | + ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.playwright-version.outputs.version }} + + - name: Install Playwright dependencies (uncached) + run: npx playwright install chromium webkit firefox --with-deps + if: steps.playwright-cache.outputs.cache-hit != 'true' + shell: bash + + - name: Install Playwright system dependencies only (cached) + run: npx playwright install-deps chromium webkit firefox + if: steps.playwright-cache.outputs.cache-hit == 'true' + shell: bash diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c160b8752a26..647d08b3feff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,6 @@ env: ${{ github.workspace }}/node_modules ${{ github.workspace }}/packages/*/node_modules ${{ github.workspace }}/dev-packages/*/node_modules - ~/.cache/ms-playwright/ ~/.cache/mongodb-binaries/ # DEPENDENCY_CACHE_KEY: can't be set here because we don't have access to yarn.lock @@ -659,26 +658,10 @@ jobs: uses: ./.github/actions/restore-cache env: DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Get npm cache directory - id: npm-cache-dir - run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT - - name: Get Playwright version - id: playwright-version - run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT - - uses: actions/cache@v4 - name: Check if Playwright browser is cached - id: playwright-cache - with: - path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-Playwright-${{steps.playwright-version.outputs.version}} - - name: Install Playwright browser if not cached - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: npx playwright install --with-deps - env: - PLAYWRIGHT_BROWSERS_PATH: ${{steps.npm-cache-dir.outputs.dir}} - - name: Install OS dependencies of Playwright if cache hit - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: npx playwright install-deps + + - name: Install Playwright + uses: ./.github/actions/install-playwright + - name: Run Playwright tests env: PW_BUNDLE: ${{ matrix.bundle }} @@ -723,26 +706,10 @@ jobs: uses: ./.github/actions/restore-cache env: DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} - - name: Get npm cache directory - id: npm-cache-dir - run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT - - name: Get Playwright version - id: playwright-version - run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT - - uses: actions/cache@v4 - name: Check if Playwright browser is cached - id: playwright-cache - with: - path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-Playwright-${{steps.playwright-version.outputs.version}} - - name: Install Playwright browser if not cached - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: npx playwright install --with-deps - env: - PLAYWRIGHT_BROWSERS_PATH: ${{steps.npm-cache-dir.outputs.dir}} - - name: Install OS dependencies of Playwright if cache hit - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: npx playwright install-deps + + - name: Install Playwright + uses: ./.github/actions/install-playwright + - name: Run Playwright Loader tests env: PW_BUNDLE: ${{ matrix.bundle }} @@ -854,6 +821,8 @@ jobs: uses: ./.github/actions/restore-cache env: DEPENDENCY_CACHE_KEY: ${{ needs.job_build.outputs.dependency_cache_key }} + - name: Install Playwright + uses: ./.github/actions/install-playwright - name: Run integration tests env: NODE_VERSION: ${{ matrix.node }} @@ -1052,6 +1021,9 @@ jobs: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + - name: Install Playwright + uses: ./.github/actions/install-playwright + - name: Get node version id: versions run: | @@ -1146,6 +1118,9 @@ jobs: path: ${{ github.workspace }}/packages/*/*.tgz key: ${{ env.BUILD_CACHE_TARBALL_KEY }} + - name: Install Playwright + uses: ./.github/actions/install-playwright + - name: Get node version id: versions run: | @@ -1243,6 +1218,9 @@ jobs: key: ${{ env.BUILD_CACHE_TARBALL_KEY }} fail-on-cache-miss : true + - name: Install Playwright + uses: ./.github/actions/install-playwright + - name: Get node version id: versions run: | diff --git a/.github/workflows/flaky-test-detector.yml b/.github/workflows/flaky-test-detector.yml index 44edf51fd45d..d2238ce58e71 100644 --- a/.github/workflows/flaky-test-detector.yml +++ b/.github/workflows/flaky-test-detector.yml @@ -49,26 +49,8 @@ jobs: - name: Build packages run: yarn build - - name: Get npm cache directory - id: npm-cache-dir - run: echo "dir=$(npm config get cache)" >> $GITHUB_OUTPUT - - name: Get Playwright version - id: playwright-version - run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> $GITHUB_OUTPUT - - uses: actions/cache@v4 - name: Check if Playwright browser is cached - id: playwright-cache - with: - path: ${{ steps.npm-cache-dir.outputs.dir }} - key: ${{ runner.os }}-Playwright-${{steps.playwright-version.outputs.version}} - - name: Install Playwright browser if not cached - if: steps.playwright-cache.outputs.cache-hit != 'true' - run: npx playwright install --with-deps - env: - PLAYWRIGHT_BROWSERS_PATH: ${{steps.npm-cache-dir.outputs.dir}} - - name: Install OS dependencies of Playwright if cache hit - if: steps.playwright-cache.outputs.cache-hit == 'true' - run: npx playwright install-deps + - name: Install Playwright + uses: ./.github/actions/install-playwright - name: Determine changed tests uses: dorny/paths-filter@v3.0.1 From c1052ab86a37b6d46f7a54d90f665cc26bdfd0fe Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Mon, 5 Aug 2024 16:29:36 +0200 Subject: [PATCH 02/11] feat(nestjs): Filter RPC exceptions (#13227) `RpcExceptions` are always explicitly thrown in nest. Therefore, they are expected for users and should not be sent to Sentry. This PR filters these exceptions. In `@sentry/nestjs` we can simply use `instanceof RpcExceptions` to achieve this. In `@sentry/node` we do not have access to this class, so we need to check based on a property. [ref](https://github.com/getsentry/sentry-javascript/issues/13190) --- .../nestjs-basic/package.json | 1 + .../nestjs-basic/src/app.controller.ts | 5 ++++ .../nestjs-basic/src/app.service.ts | 5 ++++ .../nestjs-basic/tests/errors.test.ts | 25 +++++++++++++++++++ .../node-nestjs-basic/package.json | 1 + .../node-nestjs-basic/src/app.controller.ts | 5 ++++ .../node-nestjs-basic/src/app.service.ts | 5 ++++ .../node-nestjs-basic/tests/errors.test.ts | 25 +++++++++++++++++++ packages/nestjs/package.json | 6 +++-- packages/nestjs/src/setup.ts | 3 ++- .../src/integrations/tracing/nest/nest.ts | 14 ++++++++--- yarn.lock | 8 ++++++ 12 files changed, 96 insertions(+), 7 deletions(-) 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 f4c44ff7cef3..f7a0da2fc403 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/package.json @@ -17,6 +17,7 @@ "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", "@nestjs/schedule": "^4.1.0", "@nestjs/platform-express": "^10.0.0", "@sentry/nestjs": "latest || *", diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts index c04fd5613e95..5becddbc05e0 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts @@ -49,6 +49,11 @@ export class AppController { return this.appService.testExpected500Exception(id); } + @Get('test-expected-rpc-exception/:id') + async testExpectedRpcException(@Param('id') id: string) { + return this.appService.testExpectedRpcException(id); + } + @Get('test-span-decorator-async') async testSpanDecoratorAsync() { return { result: await this.appService.testSpanDecoratorAsync() }; diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.service.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.service.ts index b2dadbb0a269..f1c935257013 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.service.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.service.ts @@ -1,4 +1,5 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { RpcException } from '@nestjs/microservices'; import { Cron, SchedulerRegistry } from '@nestjs/schedule'; import * as Sentry from '@sentry/nestjs'; import { SentryCron, SentryTraced } from '@sentry/nestjs'; @@ -38,6 +39,10 @@ export class AppService { throw new HttpException(`This is an expected 500 exception with id ${id}`, HttpStatus.INTERNAL_SERVER_ERROR); } + testExpectedRpcException(id: string) { + throw new RpcException(`This is an expected RPC exception with id ${id}`); + } + @SentryTraced('wait and return a string') async wait() { await new Promise(resolve => setTimeout(resolve, 500)); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts index cffc5f4946a3..ccc919cdd025 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts @@ -69,3 +69,28 @@ test('Does not send HttpExceptions to Sentry', async ({ baseURL }) => { expect(errorEventOccurred).toBe(false); }); + +test('Does not send RpcExceptions to Sentry', async ({ baseURL }) => { + let errorEventOccurred = false; + + waitForError('nestjs-basic', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'This is an expected RPC exception with id 123') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /test-expected-rpc-exception/:id'; + }); + + const transactionEventPromise = waitForTransaction('nestjs-basic', transactionEvent => { + return transactionEvent?.transaction === 'GET /test-expected-rpc-exception/:id'; + }); + + const response = await fetch(`${baseURL}/test-expected-rpc-exception/123`); + expect(response.status).toBe(500); + + await transactionEventPromise; + + await new Promise(resolve => setTimeout(resolve, 10000)); + + expect(errorEventOccurred).toBe(false); +}); diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/package.json b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/package.json index ec6510ac03ff..b7334026d18f 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/package.json +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/package.json @@ -17,6 +17,7 @@ "dependencies": { "@nestjs/common": "^10.0.0", "@nestjs/core": "^10.0.0", + "@nestjs/microservices": "^10.0.0", "@nestjs/schedule": "^4.1.0", "@nestjs/platform-express": "^10.0.0", "@sentry/nestjs": "latest || *", diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts index c04fd5613e95..5becddbc05e0 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts @@ -49,6 +49,11 @@ export class AppController { return this.appService.testExpected500Exception(id); } + @Get('test-expected-rpc-exception/:id') + async testExpectedRpcException(@Param('id') id: string) { + return this.appService.testExpectedRpcException(id); + } + @Get('test-span-decorator-async') async testSpanDecoratorAsync() { return { result: await this.appService.testSpanDecoratorAsync() }; diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.service.ts b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.service.ts index b2dadbb0a269..f1c935257013 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.service.ts +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.service.ts @@ -1,4 +1,5 @@ import { HttpException, HttpStatus, Injectable } from '@nestjs/common'; +import { RpcException } from '@nestjs/microservices'; import { Cron, SchedulerRegistry } from '@nestjs/schedule'; import * as Sentry from '@sentry/nestjs'; import { SentryCron, SentryTraced } from '@sentry/nestjs'; @@ -38,6 +39,10 @@ export class AppService { throw new HttpException(`This is an expected 500 exception with id ${id}`, HttpStatus.INTERNAL_SERVER_ERROR); } + testExpectedRpcException(id: string) { + throw new RpcException(`This is an expected RPC exception with id ${id}`); + } + @SentryTraced('wait and return a string') async wait() { await new Promise(resolve => setTimeout(resolve, 500)); diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts index 11eafc38f430..171f42920487 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts @@ -69,3 +69,28 @@ test('Does not send HttpExceptions to Sentry', async ({ baseURL }) => { expect(errorEventOccurred).toBe(false); }); + +test('Does not send RpcExceptions to Sentry', async ({ baseURL }) => { + let errorEventOccurred = false; + + waitForError('node-nestjs-basic', event => { + if (!event.type && event.exception?.values?.[0]?.value === 'This is an expected RPC exception with id 123') { + errorEventOccurred = true; + } + + return event?.transaction === 'GET /test-expected-rpc-exception/:id'; + }); + + const transactionEventPromise = waitForTransaction('node-nestjs-basic', transactionEvent => { + return transactionEvent?.transaction === 'GET /test-expected-rpc-exception/:id'; + }); + + const response = await fetch(`${baseURL}/test-expected-rpc-exception/123`); + expect(response.status).toBe(500); + + await transactionEventPromise; + + await new Promise(resolve => setTimeout(resolve, 10000)); + + expect(errorEventOccurred).toBe(false); +}); diff --git a/packages/nestjs/package.json b/packages/nestjs/package.json index cc35e0c33a5c..d218c0be07c2 100644 --- a/packages/nestjs/package.json +++ b/packages/nestjs/package.json @@ -51,11 +51,13 @@ }, "devDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/microservices": "^8.0.0 || ^9.0.0 || ^10.0.0" }, "peerDependencies": { "@nestjs/common": "^8.0.0 || ^9.0.0 || ^10.0.0", - "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0" + "@nestjs/core": "^8.0.0 || ^9.0.0 || ^10.0.0", + "@nestjs/microservices": "^8.0.0 || ^9.0.0 || ^10.0.0" }, "scripts": { "build": "run-p build:transpile build:types", diff --git a/packages/nestjs/src/setup.ts b/packages/nestjs/src/setup.ts index f788ccb9b67c..b068ed052a91 100644 --- a/packages/nestjs/src/setup.ts +++ b/packages/nestjs/src/setup.ts @@ -11,6 +11,7 @@ import { Catch } from '@nestjs/common'; import { Injectable } from '@nestjs/common'; import { Global, Module } from '@nestjs/common'; import { APP_FILTER, APP_INTERCEPTOR, BaseExceptionFilter } from '@nestjs/core'; +import { RpcException } from '@nestjs/microservices'; import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, @@ -68,7 +69,7 @@ class SentryGlobalFilter extends BaseExceptionFilter { */ public catch(exception: unknown, host: ArgumentsHost): void { // don't report expected errors - if (exception instanceof HttpException) { + if (exception instanceof HttpException || exception instanceof RpcException) { return super.catch(exception, host); } diff --git a/packages/node/src/integrations/tracing/nest/nest.ts b/packages/node/src/integrations/tracing/nest/nest.ts index 4f7f7a1f59d3..4f8d88fa8f86 100644 --- a/packages/node/src/integrations/tracing/nest/nest.ts +++ b/packages/node/src/integrations/tracing/nest/nest.ts @@ -87,10 +87,16 @@ export function setupNestErrorHandler(app: MinimalNestJsApp, baseFilter: NestJsE const originalCatch = Reflect.get(target, prop, receiver); return (exception: unknown, host: unknown) => { - const status_code = (exception as { status?: number }).status; - - // don't report expected errors - if (status_code !== undefined) { + const exceptionIsObject = typeof exception === 'object' && exception !== null; + const exceptionStatusCode = exceptionIsObject && 'status' in exception ? exception.status : null; + const exceptionErrorProperty = exceptionIsObject && 'error' in exception ? exception.error : null; + + /* + Don't report expected NestJS control flow errors + - `HttpException` errors will have a `status` property + - `RpcException` errors will have an `error` property + */ + if (exceptionStatusCode !== null || exceptionErrorProperty !== null) { return originalCatch.apply(target, [exception, host]); } diff --git a/yarn.lock b/yarn.lock index 953f0eee5f3a..660c53cce594 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6135,6 +6135,14 @@ path-to-regexp "3.2.0" tslib "2.6.3" +"@nestjs/microservices@^8.0.0 || ^9.0.0 || ^10.0.0": + version "10.3.10" + resolved "https://registry.yarnpkg.com/@nestjs/microservices/-/microservices-10.3.10.tgz#e00957e0c22b0cc8b041242a40538e2d862255fb" + integrity sha512-zZrilhZmXU2Ik5Usrcy4qEX262Uhvz0/9XlIdX6SRn8I39ns1EE9tAhEBmmkMwh7lsEikRFa4aaa05loi8Gsow== + dependencies: + iterare "1.2.1" + tslib "2.6.3" + "@nestjs/platform-express@^10.3.3": version "10.3.3" resolved "https://registry.yarnpkg.com/@nestjs/platform-express/-/platform-express-10.3.3.tgz#c1484d30d1e7666c4c8d0d7cde31cfc0b9d166d7" From c71177b7d7da81cf1b7634e09e4c4ee8b979f8b5 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 5 Aug 2024 17:23:49 +0200 Subject: [PATCH 03/11] ci: Improve CI dependency checks (#13175) This PR updates the way we detect changed packages to rely on Nx under the hood, which should always be in sync. Previously, we hard-coded paths in the GH workflow to determine which packages have been changed, so we can make sure to run tests accordingly. Now, we use Nx to detect this for PRs - this takes the dependency graph into consideration and should always be up-to-date. We just need to make sure to have correct dependencies defined, also for dev packages like node-integration-tests (see addition I made there). Note: For profiling-node, we still check the old way, because we want to avoid re-running this every time a dependency of profiling-node changes - because that depends on e.g. core and utils, and we don't want to/need to re-run this all the time. This PR does two other things: 1. Enable global yarn cache - this may help us reduce install time on CI 2. Merge the install & build CI steps - these were run in parallel, which in reality only ate up about 50s, because this is how long it takes to restore the dependency cache, which had to happen in the build step. By merging this, min. time for install + build for a fully cached scenario is down to ~1:15 minutes, where previously it was >2 minutes across the two steps. Example runs: * Change in packages/browser: https://github.com/getsentry/sentry-javascript/actions/runs/10215948246 * Change in packages/core: https://github.com/getsentry/sentry-javascript/actions/runs/10215944443 * Change in packages/profiling-node: https://github.com/getsentry/sentry-javascript/actions/runs/10216003595 --- .github/workflows/build.yml | 201 ++++++------------ .../node-integration-tests/package.json | 2 + 2 files changed, 67 insertions(+), 136 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 647d08b3feff..6eea92c884ef 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -73,6 +73,7 @@ jobs: # We need to check out not only the fake merge commit between the PR and the base branch which GH creates, but # also its parents, so that we can pull the commit message from the head commit of the PR fetch-depth: 2 + - name: Get metadata id: get_metadata # We need to try a number of different options for finding the head commit, because each kind of trigger event @@ -82,79 +83,20 @@ jobs: echo "COMMIT_SHA=$COMMIT_SHA" >> $GITHUB_ENV echo "COMMIT_MESSAGE=$(git log -n 1 --pretty=format:%s $COMMIT_SHA)" >> $GITHUB_ENV + # Most changed packages are determined in job_build via Nx + # However, for profiling-node we only want to run certain things when in this specific package + # something changed, not in any of the dependencies (which include core, utils, ...) - name: Determine changed packages uses: dorny/paths-filter@v3.0.1 id: changed with: filters: | - workflow: &workflow + workflow: - '.github/**' - shared: &shared - - *workflow - - '*.{js,ts,json,yml,lock}' - - 'CHANGELOG.md' - - 'jest/**' - - 'scripts/**' - - 'packages/core/**' - - 'packages/rollup-utils/**' - - 'packages/utils/**' - - 'packages/types/**' - - 'dev-packages/test-utils/**' - browser: &browser - - *shared - - 'packages/browser/**' - - 'packages/browser-utils/**' - - 'packages/replay-internal/**' - - 'packages/replay-worker/**' - - 'packages/replay-canvas/**' - - 'packages/feedback/**' - - 'packages/wasm/**' - node: &node - - *shared - - 'packages/node/**' - - 'packages/opentelemetry/**' - browser_integration: - - *shared - - *browser - - 'dev-packages/browser-integration-tests/**' - ember: - - *shared - - *browser - - 'packages/ember/**' - node_integration: - - *shared - - *node - - 'dev-packages/node-integration-tests/**' - - 'packages/nestjs/**' - nextjs: - - *shared - - *browser - - *node - - 'packages/nextjs/**' - - 'packages/react/**' - - 'packages/vercel-edge/**' - remix: - - *shared - - *browser - - *node - - 'packages/remix/**' - - 'packages/react/**' profiling_node: - - *shared - - 'packages/node/**' - - 'packages/profiling-node/**' - - 'dev-packages/e2e-tests/test-applications/node-profiling/**' - profiling_node_bindings: - 'packages/profiling-node/**' - 'dev-packages/e2e-tests/test-applications/node-profiling/**' - deno: - - *shared - - 'packages/deno/**' - bun: - - *shared - - 'packages/bun/**' - any_code: - - '!**/*.md' + - name: Get PR labels id: pr-labels @@ -162,21 +104,11 @@ jobs: outputs: commit_label: '${{ env.COMMIT_SHA }}: ${{ env.COMMIT_MESSAGE }}' - changed_nextjs: ${{ steps.changed.outputs.nextjs }} - changed_ember: ${{ steps.changed.outputs.ember }} - changed_remix: ${{ steps.changed.outputs.remix }} - changed_node: ${{ steps.changed.outputs.node }} - changed_node_integration: ${{ steps.changed.outputs.node_integration }} - changed_profiling_node: ${{ steps.changed.outputs.profiling_node }} - changed_profiling_node_bindings: ${{ steps.changed.outputs.profiling_node_bindings }} - changed_deno: ${{ steps.changed.outputs.deno }} - changed_bun: ${{ steps.changed.outputs.bun }} - changed_browser: ${{ steps.changed.outputs.browser }} - changed_browser_integration: ${{ steps.changed.outputs.browser_integration }} - changed_any_code: ${{ steps.changed.outputs.any_code }} # Note: These next three have to be checked as strings ('true'/'false')! is_develop: ${{ github.ref == 'refs/heads/develop' }} is_release: ${{ startsWith(github.ref, 'refs/heads/release/') }} + changed_profiling_node: ${{ steps.changed.outputs.profiling_node == 'true' }} + changed_ci: ${{ steps.changed.outputs.workflow == 'true' }} # When merging into master, or from master is_gitflow_sync: ${{ github.head_ref == 'master' || github.ref == 'refs/heads/master' }} has_gitflow_label: @@ -185,22 +117,30 @@ jobs: ${{ github.event_name == 'schedule' || (github.event_name == 'pull_request' && contains(steps.pr-labels.outputs.labels, ' ci-skip-cache ')) }} - job_install_deps: - name: Install Dependencies + job_build: + name: Build needs: job_get_metadata runs-on: ubuntu-20.04 timeout-minutes: 15 if: | (needs.job_get_metadata.outputs.is_gitflow_sync == 'false' && needs.job_get_metadata.outputs.has_gitflow_label == 'false') steps: + - name: Check out base commit (${{ github.event.pull_request.base.sha }}) + uses: actions/checkout@v4 + if: github.event_name == 'pull_request' + with: + ref: ${{ github.event.pull_request.base.sha }} + - name: 'Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }})' uses: actions/checkout@v4 with: ref: ${{ env.HEAD_COMMIT }} + - name: Set up Node uses: actions/setup-node@v4 with: node-version-file: 'package.json' + # we use a hash of yarn.lock as our cache key, because if it hasn't changed, our dependencies haven't changed, # so no need to reinstall them - name: Compute dependency cache key @@ -217,46 +157,14 @@ jobs: - name: Install dependencies if: steps.cache_dependencies.outputs.cache-hit != 'true' run: yarn install --ignore-engines --frozen-lockfile - outputs: - dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }} - - job_check_branches: - name: Check PR branches - needs: job_get_metadata - runs-on: ubuntu-20.04 - if: github.event_name == 'pull_request' - permissions: - pull-requests: write - steps: - - name: PR is opened against master - uses: mshick/add-pr-comment@dd126dd8c253650d181ad9538d8b4fa218fc31e8 - if: ${{ github.base_ref == 'master' && !startsWith(github.head_ref, 'prepare-release/') }} - with: - message: | - ⚠️ This PR is opened against **master**. You probably want to open it against **develop**. - job_build: - name: Build - needs: [job_get_metadata, job_install_deps] - runs-on: ubuntu-20.04-large-js - timeout-minutes: 30 - if: | - (needs.job_get_metadata.outputs.changed_any_code == 'true' || github.event_name != 'pull_request') - steps: - - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) - uses: actions/checkout@v4 - with: - ref: ${{ env.HEAD_COMMIT }} - - name: Set up Node - uses: actions/setup-node@v4 - with: - node-version-file: 'package.json' - - name: Check dependency cache - uses: actions/cache/restore@v4 + - name: Check for Affected Nx Projects + uses: dkhunt27/action-nx-affected-list@v5.3 + id: checkForAffected + if: github.event_name == 'pull_request' with: - path: ${{ env.CACHED_DEPENDENCY_PATHS }} - key: ${{ needs.job_install_deps.outputs.dependency_cache_key }} - fail-on-cache-miss: true + base: ${{ github.event.pull_request.base.sha }} + head: ${{ env.HEAD_COMMIT }} - name: Check build cache uses: actions/cache@v4 @@ -285,10 +193,31 @@ jobs: env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: yarn build + outputs: - # this needs to be passed on, because the `needs` context only looks at direct ancestors (so steps which depend on - # `job_build` can't see `job_install_deps` and what it returned) - dependency_cache_key: ${{ needs.job_install_deps.outputs.dependency_cache_key }} + dependency_cache_key: ${{ steps.compute_lockfile_hash.outputs.hash }} + changed_node_integration: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry-internal/node-integration-tests') }} + changed_remix: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/remix') }} + changed_node: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/node') }} + changed_deno: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/deno') }} + changed_bun: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry/bun') }} + changed_browser_integration: ${{ needs.job_get_metadata.outputs.changed_ci == 'true' || contains(steps.checkForAffected.outputs.affected, '@sentry-internal/browser-integration-tests') }} + # If you are looking for changed_profiling_node, this is defined in job_get_metadata + + job_check_branches: + name: Check PR branches + needs: job_get_metadata + runs-on: ubuntu-20.04 + if: github.event_name == 'pull_request' + permissions: + pull-requests: write + steps: + - name: PR is opened against master + uses: mshick/add-pr-comment@dd126dd8c253650d181ad9538d8b4fa218fc31e8 + if: ${{ github.base_ref == 'master' && !startsWith(github.head_ref, 'prepare-release/') }} + with: + message: | + ⚠️ This PR is opened against **master**. You probably want to open it against **develop**. job_size_check: name: Size Check @@ -345,7 +274,7 @@ jobs: job_check_format: name: Check file formatting - needs: [job_get_metadata, job_install_deps] + needs: [job_get_metadata, job_build] timeout-minutes: 10 runs-on: ubuntu-20.04 steps: @@ -361,7 +290,7 @@ jobs: uses: actions/cache/restore@v4 with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} - key: ${{ needs.job_install_deps.outputs.dependency_cache_key }} + key: ${{ needs.job_build.outputs.dependency_cache_key }} fail-on-cache-miss: true - name: Check file formatting run: yarn lint:prettier && yarn lint:biome @@ -437,6 +366,7 @@ jobs: steps: - name: Check out base commit (${{ github.event.pull_request.base.sha }}) uses: actions/checkout@v4 + if: github.event_name == 'pull_request' with: ref: ${{ github.event.pull_request.base.sha }} @@ -469,7 +399,7 @@ jobs: job_bun_unit_tests: name: Bun Unit Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_bun == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_bun == 'true' || github.event_name != 'pull_request' timeout-minutes: 10 runs-on: ubuntu-20.04 strategy: @@ -496,7 +426,7 @@ jobs: job_deno_unit_tests: name: Deno Unit Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_deno == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_deno == 'true' || github.event_name != 'pull_request' timeout-minutes: 10 runs-on: ubuntu-20.04 strategy: @@ -536,6 +466,7 @@ jobs: steps: - name: Check out base commit (${{ github.event.pull_request.base.sha }}) uses: actions/checkout@v4 + if: github.event_name == 'pull_request' with: ref: ${{ github.event.pull_request.base.sha }} - name: Check out current commit (${{ needs.job_get_metadata.outputs.commit_label }}) @@ -571,7 +502,7 @@ jobs: job_profiling_node_unit_tests: name: Node Profiling Unit Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_node == 'true' || needs.job_get_metadata.outputs.changed_profiling_node == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_node == 'true' || needs.job_get_metadata.outputs.changed_profiling_node == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-latest timeout-minutes: 10 steps: @@ -599,7 +530,7 @@ jobs: job_browser_playwright_tests: name: Playwright (${{ matrix.bundle }}${{ matrix.shard && format(' {0}/{1}', matrix.shard, matrix.shards) || ''}}) Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-20.04-large-js timeout-minutes: 25 strategy: @@ -674,11 +605,10 @@ jobs: name: playwright-traces path: dev-packages/browser-integration-tests/test-results - job_browser_loader_tests: name: Playwright Loader (${{ matrix.bundle }}) Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_browser_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-20.04 timeout-minutes: 15 strategy: @@ -748,13 +678,12 @@ jobs: exit 1 fi - job_node_integration_tests: name: Node (${{ matrix.node }})${{ (matrix.typescript && format(' (TS {0})', matrix.typescript)) || '' }} Integration Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_node_integration == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_node_integration == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-20.04 timeout-minutes: 15 strategy: @@ -796,7 +725,7 @@ jobs: job_remix_integration_tests: name: Remix v${{ matrix.remix }} (Node ${{ matrix.node }}) Tests needs: [job_get_metadata, job_build] - if: needs.job_get_metadata.outputs.changed_remix == 'true' || github.event_name != 'pull_request' + if: needs.job_build.outputs.changed_remix == 'true' || github.event_name != 'pull_request' runs-on: ubuntu-20.04 timeout-minutes: 10 strategy: @@ -866,14 +795,14 @@ jobs: # Rebuild profiling by compiling TS and pull the precompiled binary artifacts - name: Build Profiling Node if: | - (needs.job_get_metadata.outputs.changed_profiling_node_bindings == 'true') || + (needs.job_get_metadata.outputs.changed_profiling_node == 'true') || (needs.job_get_metadata.outputs.is_release == 'true') || (github.event_name != 'pull_request') run: yarn lerna run build:lib --scope @sentry/profiling-node - name: Extract Profiling Node Prebuilt Binaries if: | - (needs.job_get_metadata.outputs.changed_profiling_node_bindings == 'true') || + (needs.job_get_metadata.outputs.changed_profiling_node == 'true') || (needs.job_get_metadata.outputs.is_release == 'true') || (github.event_name != 'pull_request') uses: actions/download-artifact@v4 @@ -1167,7 +1096,7 @@ jobs: always() && needs.job_e2e_prepare.result == 'success' && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && ( - (needs.job_get_metadata.outputs.changed_profiling_node_bindings == 'true') || + (needs.job_get_metadata.outputs.changed_profiling_node == 'true') || (needs.job_get_metadata.outputs.is_release == 'true') || (github.event_name != 'pull_request') ) @@ -1320,11 +1249,11 @@ jobs: 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' }} - needs: [job_get_metadata, job_install_deps, job_build] + 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. if: | - (needs.job_get_metadata.outputs.changed_profiling_node_bindings == 'true') || + (needs.job_get_metadata.outputs.changed_profiling_node == 'true') || (needs.job_get_metadata.outputs.is_release == 'true') || (github.event_name != 'pull_request') runs-on: ${{ matrix.os }} @@ -1481,7 +1410,7 @@ jobs: id: restore-dependencies with: path: ${{ env.CACHED_DEPENDENCY_PATHS }} - key: ${{ needs.job_install_deps.outputs.dependency_cache_key }} + key: ${{ needs.job_build.outputs.dependency_cache_key }} enableCrossOsArchive: true - name: Restore build cache diff --git a/dev-packages/node-integration-tests/package.json b/dev-packages/node-integration-tests/package.json index 19a8898fe90c..5a94953e054e 100644 --- a/dev-packages/node-integration-tests/package.json +++ b/dev-packages/node-integration-tests/package.json @@ -31,7 +31,9 @@ "@nestjs/core": "^10.3.3", "@nestjs/platform-express": "^10.3.3", "@prisma/client": "5.9.1", + "@sentry/aws-serverless": "8.23.0", "@sentry/node": "8.23.0", + "@sentry/utils": "8.23.0", "@sentry/types": "8.23.0", "@types/mongodb": "^3.6.20", "@types/mysql": "^2.15.21", From 420aaf8fb8ce0123b9d139bfce924823f2cb6866 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 5 Aug 2024 17:56:52 +0200 Subject: [PATCH 04/11] test(nuxt): Unit tests for event filter (#13229) Adding more convenient unit test. There is already an E2E test for this: https://github.com/getsentry/sentry-javascript/blob/b6cf7b0cabc27a84e962f0a1e408465cc87fd961/dev-packages/e2e-tests/test-applications/nuxt-3/tests/performance.server.test.ts#L24 Also moved two files in the `test` folder to resemble the `src` folder --- .../plugins/server.test.ts} | 0 .../test/{client => }/runtime/utils.test.ts | 2 +- packages/nuxt/test/server/sdk.test.ts | 43 +++++++++++++++++++ 3 files changed, 44 insertions(+), 1 deletion(-) rename packages/nuxt/test/{server/runtime/plugin.test.ts => runtime/plugins/server.test.ts} (100%) rename packages/nuxt/test/{client => }/runtime/utils.test.ts (97%) diff --git a/packages/nuxt/test/server/runtime/plugin.test.ts b/packages/nuxt/test/runtime/plugins/server.test.ts similarity index 100% rename from packages/nuxt/test/server/runtime/plugin.test.ts rename to packages/nuxt/test/runtime/plugins/server.test.ts diff --git a/packages/nuxt/test/client/runtime/utils.test.ts b/packages/nuxt/test/runtime/utils.test.ts similarity index 97% rename from packages/nuxt/test/client/runtime/utils.test.ts rename to packages/nuxt/test/runtime/utils.test.ts index b0b039d52e54..08c66193caa3 100644 --- a/packages/nuxt/test/client/runtime/utils.test.ts +++ b/packages/nuxt/test/runtime/utils.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { extractErrorContext } from '../../../src/runtime/utils'; +import { extractErrorContext } from '../../src/runtime/utils'; describe('extractErrorContext', () => { it('returns empty object for undefined or empty context', () => { diff --git a/packages/nuxt/test/server/sdk.test.ts b/packages/nuxt/test/server/sdk.test.ts index 8d84dc8b15c8..20ec11c33512 100644 --- a/packages/nuxt/test/server/sdk.test.ts +++ b/packages/nuxt/test/server/sdk.test.ts @@ -1,4 +1,5 @@ import * as SentryNode from '@sentry/node'; +import type { NodeClient } from '@sentry/node'; import { SDK_VERSION } from '@sentry/node'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { init } from '../../src/server'; @@ -38,5 +39,47 @@ describe('Nuxt Server SDK', () => { it('returns client from init', () => { expect(init({})).not.toBeUndefined(); }); + + it('filters out low quality transactions', async () => { + const beforeSendEvent = vi.fn(event => event); + const client = init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + }) as NodeClient; + client.on('beforeSendEvent', beforeSendEvent); + + client.captureEvent({ type: 'transaction', transaction: 'GET /' }); + client.captureEvent({ type: 'transaction', transaction: 'GET /_nuxt/some_asset.js' }); + // Although this has the name of the build asset directory (_nuxt), it should not be filtered out as it would not match the regex + client.captureEvent({ type: 'transaction', transaction: 'GET _nuxt/some_asset.js' }); + client.captureEvent({ type: 'transaction', transaction: 'POST /_server' }); + + await client!.flush(); + + expect(beforeSendEvent).toHaveBeenCalledTimes(3); + expect(beforeSendEvent).toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'GET /', + }), + expect.any(Object), + ); + expect(beforeSendEvent).toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'GET _nuxt/some_asset.js', + }), + expect.any(Object), + ); + expect(beforeSendEvent).not.toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'GET /_nuxt/some_asset.js', + }), + expect.any(Object), + ); + expect(beforeSendEvent).toHaveBeenCalledWith( + expect.objectContaining({ + transaction: 'POST /_server', + }), + expect.any(Object), + ); + }); }); }); From ea20c21b157edd0912313228ea22199895a5a3b8 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 5 Aug 2024 19:25:39 +0200 Subject: [PATCH 05/11] test(e2e): Fix event buffering (#13233) --- .../e2e-tests/Dockerfile.publish-packages | 2 +- dev-packages/e2e-tests/publish-packages.ts | 23 +++- .../aws-serverless-esm/start-event-proxy.mjs | 1 - .../test-utils/src/event-proxy-server.ts | 103 ++++-------------- 4 files changed, 42 insertions(+), 87 deletions(-) diff --git a/dev-packages/e2e-tests/Dockerfile.publish-packages b/dev-packages/e2e-tests/Dockerfile.publish-packages index 4d5b2ba3abf3..88fd7f116728 100644 --- a/dev-packages/e2e-tests/Dockerfile.publish-packages +++ b/dev-packages/e2e-tests/Dockerfile.publish-packages @@ -3,4 +3,4 @@ ARG NODE_VERSION=18.18.0 FROM node:${NODE_VERSION} WORKDIR /sentry-javascript/dev-packages/e2e-tests -CMD [ "yarn", "ts-node", "publish-packages.ts" ] +CMD [ "yarn", "ts-node", "publish-packages.ts", "--transpile-only" ] diff --git a/dev-packages/e2e-tests/publish-packages.ts b/dev-packages/e2e-tests/publish-packages.ts index 2be19b173bd3..408d046977a2 100644 --- a/dev-packages/e2e-tests/publish-packages.ts +++ b/dev-packages/e2e-tests/publish-packages.ts @@ -13,9 +13,22 @@ const packageTarballPaths = glob.sync('packages/*/sentry-*.tgz', { // Publish built packages to the fake registry packageTarballPaths.forEach(tarballPath => { // `--userconfig` flag needs to be before `publish` - childProcess.execSync(`npm --userconfig ${__dirname}/test-registry.npmrc publish ${tarballPath}`, { - cwd: repositoryRoot, // Can't use __dirname here because npm would try to publish `@sentry-internal/e2e-tests` - encoding: 'utf8', - stdio: 'inherit', - }); + childProcess.exec( + `npm --userconfig ${__dirname}/test-registry.npmrc publish ${tarballPath}`, + { + cwd: repositoryRoot, // Can't use __dirname here because npm would try to publish `@sentry-internal/e2e-tests` + encoding: 'utf8', + }, + (err, stdout, stderr) => { + // eslint-disable-next-line no-console + console.log(stdout); + // eslint-disable-next-line no-console + console.log(stderr); + if (err) { + // eslint-disable-next-line no-console + console.error(err); + process.exit(1); + } + }, + ); }); diff --git a/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs b/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs index e74f395b6237..86605fcb7b9a 100644 --- a/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs +++ b/dev-packages/e2e-tests/test-applications/aws-serverless-esm/start-event-proxy.mjs @@ -3,5 +3,4 @@ import { startEventProxyServer } from '@sentry-internal/test-utils'; startEventProxyServer({ port: 3031, proxyServerName: 'aws-serverless-esm', - forwardToSentry: false, }); diff --git a/dev-packages/test-utils/src/event-proxy-server.ts b/dev-packages/test-utils/src/event-proxy-server.ts index 58c39de95c8c..17922a4f90aa 100644 --- a/dev-packages/test-utils/src/event-proxy-server.ts +++ b/dev-packages/test-utils/src/event-proxy-server.ts @@ -1,5 +1,4 @@ /* eslint-disable max-lines */ - import * as fs from 'fs'; import * as http from 'http'; import type { AddressInfo } from 'net'; @@ -18,11 +17,6 @@ interface EventProxyServerOptions { port: number; /** The name for the proxy server used for referencing it with listener functions */ proxyServerName: string; - /** - * Whether or not to forward the event to sentry. @default `false` - * This is helpful when you can't register a tunnel in the SDK setup (e.g. lambda layer without Sentry.init call) - */ - forwardToSentry?: boolean; } interface SentryRequestCallbackData { @@ -36,12 +30,16 @@ interface EventCallbackListener { (data: string): void; } +type SentryResponseStatusCode = number; +type SentryResponseBody = string; +type SentryResponseHeaders = Record | undefined; + type OnRequest = ( eventCallbackListeners: Set, proxyRequest: http.IncomingMessage, proxyRequestBody: string, eventBuffer: BufferedEvent[], -) => Promise<[number, string, Record | undefined]>; +) => Promise<[SentryResponseStatusCode, SentryResponseBody, SentryResponseHeaders]>; interface BufferedEvent { timestamp: number; @@ -170,83 +168,28 @@ export async function startProxyServer( */ export async function startEventProxyServer(options: EventProxyServerOptions): Promise { await startProxyServer(options, async (eventCallbackListeners, proxyRequest, proxyRequestBody, eventBuffer) => { - const envelopeHeader: EnvelopeItem[0] = JSON.parse(proxyRequestBody.split('\n')[0] as string); + const data: SentryRequestCallbackData = { + envelope: parseEnvelope(proxyRequestBody), + rawProxyRequestBody: proxyRequestBody, + rawSentryResponseBody: '', + sentryResponseStatusCode: 200, + }; - const shouldForwardEventToSentry = options.forwardToSentry || false; + const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - if (!envelopeHeader.dsn && shouldForwardEventToSentry) { - // eslint-disable-next-line no-console - console.log( - '[event-proxy-server] Warn: No dsn on envelope header. Maybe a client-report was received. Proxy request body:', - proxyRequestBody, - ); - - return [200, '{}', {}]; - } - - if (!shouldForwardEventToSentry) { - const data: SentryRequestCallbackData = { - envelope: parseEnvelope(proxyRequestBody), - rawProxyRequestBody: proxyRequestBody, - rawSentryResponseBody: '', - sentryResponseStatusCode: 200, - }; - eventCallbackListeners.forEach(listener => { - listener(Buffer.from(JSON.stringify(data)).toString('base64')); - }); - - return [ - 200, - '{}', - { - 'Access-Control-Allow-Origin': '*', - }, - ]; - } - - const { origin, pathname, host } = new URL(envelopeHeader.dsn as string); - - const projectId = pathname.substring(1); - const sentryIngestUrl = `${origin}/api/${projectId}/envelope/`; - - proxyRequest.headers.host = host; - - const reqHeaders: Record = {}; - for (const [key, value] of Object.entries(proxyRequest.headers)) { - reqHeaders[key] = value as string; - } - - // Fetch does not like this - delete reqHeaders['transfer-encoding']; - - return fetch(sentryIngestUrl, { - body: proxyRequestBody, - headers: reqHeaders, - method: proxyRequest.method, - }).then(async res => { - const rawSentryResponseBody = await res.text(); - const data: SentryRequestCallbackData = { - envelope: parseEnvelope(proxyRequestBody), - rawProxyRequestBody: proxyRequestBody, - rawSentryResponseBody, - sentryResponseStatusCode: res.status, - }; - - const dataString = Buffer.from(JSON.stringify(data)).toString('base64'); - - eventBuffer.push({ data: dataString, timestamp: getNanosecondTimestamp() }); - - eventCallbackListeners.forEach(listener => { - listener(dataString); - }); - - const resHeaders: Record = {}; - for (const [key, value] of res.headers.entries()) { - resHeaders[key] = value; - } + eventBuffer.push({ data: dataString, timestamp: getNanosecondTimestamp() }); - return [res.status, rawSentryResponseBody, resHeaders]; + eventCallbackListeners.forEach(listener => { + listener(dataString); }); + + return [ + 200, + '{}', + { + 'Access-Control-Allow-Origin': '*', + }, + ]; }); } From 22905feabcc2f5b1c43aa8784b4e350103bd496a Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Tue, 6 Aug 2024 08:54:34 +0200 Subject: [PATCH 06/11] fix(feedback): Ensure feedback can be lazy loaded in CDN bundles (#13241) This was brought up in slack - if you use a CDN bundle (or the loader) without feedback included, and you try to lazy-load the feedbackIntegration, it fails as of today. The reason is that we check if `window.Sentry.feedbackIntegration` exists, which it _does_, because we register a shim integration for compatibility in the loader. So this PR adds a property on the shim integration which we can check for during lazy loading. While at it, I also added a missing method to the feedback integration shim. --- .../lazyLoad/feedbackIntegration/init.js | 10 +++++ .../lazyLoad/feedbackIntegration/subject.js | 7 ++++ .../lazyLoad/feedbackIntegration/test.ts | 38 +++++++++++++++++++ .../rollup-utils/plugins/bundlePlugins.mjs | 2 + .../browser/src/utils/lazyLoadIntegration.ts | 5 ++- packages/integration-shims/src/Feedback.ts | 33 +++++++++------- 6 files changed, 80 insertions(+), 15 deletions(-) create mode 100644 dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/init.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/subject.js create mode 100644 dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/test.ts diff --git a/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/init.js b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/init.js new file mode 100644 index 000000000000..d0ff6bbb92c9 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/init.js @@ -0,0 +1,10 @@ +import * as Sentry from '@sentry/browser'; + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + integrations: [], +}); + +window.Sentry = { + ...Sentry, +}; diff --git a/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/subject.js b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/subject.js new file mode 100644 index 000000000000..4ef2f8f41622 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/subject.js @@ -0,0 +1,7 @@ +window._testLazyLoadIntegration = async function run() { + const integration = await window.Sentry.lazyLoadIntegration('feedbackIntegration'); + + window.Sentry.getClient()?.addIntegration(integration()); + + window._integrationLoaded = true; +}; diff --git a/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/test.ts b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/test.ts new file mode 100644 index 000000000000..d054c2da2e99 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/lazyLoad/feedbackIntegration/test.ts @@ -0,0 +1,38 @@ +import { expect } from '@playwright/test'; +import { SDK_VERSION } from '@sentry/browser'; + +import { sentryTest } from '../../../../utils/fixtures'; + +sentryTest('it allows to lazy load the feedback integration', async ({ getLocalTestUrl, page }) => { + const bundle = process.env.PW_BUNDLE || ''; + const url = await getLocalTestUrl({ testDir: __dirname }); + + await page.route(`https://browser.sentry-cdn.com/${SDK_VERSION}/feedback.min.js`, route => { + return route.fulfill({ + status: 200, + contentType: 'application/javascript;', + body: "window.Sentry.feedbackIntegration = () => ({ name: 'Feedback', attachTo: () => {} })", + }); + }); + + await page.goto(url); + + await page.waitForFunction('window.Sentry?.getClient()'); + + const integrationOutput1 = await page.evaluate('window.Sentry.feedbackIntegration?._isShim'); + + // Multiple cases are possible here: + // 1. Bundle without feedback, should have _isShim property + if (bundle.startsWith('bundle') && !bundle.includes('feedback')) { + expect(integrationOutput1).toBe(true); + } else { + // 2. Either bundle with feedback, or ESM, should not have _isShim property + expect(integrationOutput1).toBe(undefined); + } + + await page.evaluate('window._testLazyLoadIntegration()'); + await page.waitForFunction('window._integrationLoaded'); + + const integrationOutput2 = await page.evaluate('window.Sentry.feedbackIntegration?._isShim'); + expect(integrationOutput2).toBe(undefined); +}); diff --git a/dev-packages/rollup-utils/plugins/bundlePlugins.mjs b/dev-packages/rollup-utils/plugins/bundlePlugins.mjs index 760fdc05daa6..ffc24f58174a 100644 --- a/dev-packages/rollup-utils/plugins/bundlePlugins.mjs +++ b/dev-packages/rollup-utils/plugins/bundlePlugins.mjs @@ -133,6 +133,8 @@ export function makeTerserPlugin() { '_sentryIsolationScope', // require-in-the-middle calls `Module._resolveFilename`. We cannot mangle this (AWS lambda layer bundle). '_resolveFilename', + // Set on e.g. the shim feedbackIntegration to be able to detect it + '_isShim', ], }, }, diff --git a/packages/browser/src/utils/lazyLoadIntegration.ts b/packages/browser/src/utils/lazyLoadIntegration.ts index 4479c2e69590..b023bc18aa95 100644 --- a/packages/browser/src/utils/lazyLoadIntegration.ts +++ b/packages/browser/src/utils/lazyLoadIntegration.ts @@ -43,7 +43,10 @@ export async function lazyLoadIntegration(name: keyof typeof LazyLoadableIntegra // Bail if the integration already exists const existing = sentryOnWindow[name]; - if (typeof existing === 'function') { + // The `feedbackIntegration` is loaded by default in the CDN bundles, + // so we need to differentiate between the real integration and the shim. + // if only the shim exists, we still want to lazy load the real integration. + if (typeof existing === 'function' && !('_isShim' in existing)) { return existing; } diff --git a/packages/integration-shims/src/Feedback.ts b/packages/integration-shims/src/Feedback.ts index 189dc074cd1e..ef4010bb0494 100644 --- a/packages/integration-shims/src/Feedback.ts +++ b/packages/integration-shims/src/Feedback.ts @@ -2,7 +2,7 @@ import type { Integration } from '@sentry/types'; import { consoleSandbox } from '@sentry/utils'; import { FAKE_FUNCTION } from './common'; -const FEEDBACK_INTEGRATION_METHODS = ['attachTo', 'createWidget', 'remove'] as const; +const FEEDBACK_INTEGRATION_METHODS = ['attachTo', 'createForm', 'createWidget', 'remove'] as const; type FeedbackSpecificMethods = Record<(typeof FEEDBACK_INTEGRATION_METHODS)[number], () => void>; @@ -13,17 +13,22 @@ interface FeedbackIntegration extends Integration, FeedbackSpecificMethods {} * It is needed in order for the CDN bundles to continue working when users add/remove feedback * from it, without changing their config. This is necessary for the loader mechanism. */ -export function feedbackIntegrationShim(_options: unknown): FeedbackIntegration { - consoleSandbox(() => { - // eslint-disable-next-line no-console - console.warn('You are using feedbackIntegration() even though this bundle does not include feedback.'); - }); +export const feedbackIntegrationShim = Object.assign( + (_options: unknown): FeedbackIntegration => { + consoleSandbox(() => { + // eslint-disable-next-line no-console + console.warn('You are using feedbackIntegration() even though this bundle does not include feedback.'); + }); - return { - name: 'Feedback', - ...(FEEDBACK_INTEGRATION_METHODS.reduce((acc, method) => { - acc[method] = FAKE_FUNCTION; - return acc; - }, {} as FeedbackSpecificMethods) as FeedbackSpecificMethods), - }; -} + return { + name: 'Feedback', + ...(FEEDBACK_INTEGRATION_METHODS.reduce((acc, method) => { + acc[method] = FAKE_FUNCTION; + return acc; + }, {} as FeedbackSpecificMethods) as FeedbackSpecificMethods), + }; + }, + { + _isShim: true, + }, +); From c8054ccd899edefa09b77a00bc62271e995c4c68 Mon Sep 17 00:00:00 2001 From: Nicolas Hrubec Date: Tue, 6 Aug 2024 09:45:41 +0200 Subject: [PATCH 07/11] tests(e2e): Remove await timeout in nest e2e tests (#13243) Adding a separate flush endpoint that flushes the client in the application so that we can remove the timeout await and speed up tests. --- .../test-applications/nestjs-basic/src/app.controller.ts | 6 ++++++ .../test-applications/nestjs-basic/tests/errors.test.ts | 4 ++-- .../nestjs-with-submodules/src/app.controller.ts | 6 ++++++ .../nestjs-with-submodules/tests/errors.test.ts | 4 ++-- .../node-nestjs-basic/src/app.controller.ts | 6 ++++++ .../node-nestjs-basic/tests/errors.test.ts | 4 ++-- 6 files changed, 24 insertions(+), 6 deletions(-) diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts index 5becddbc05e0..ec0a921da2c4 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/src/app.controller.ts @@ -1,4 +1,5 @@ import { Controller, Get, Param, ParseIntPipe, UseGuards, UseInterceptors } from '@nestjs/common'; +import { flush } from '@sentry/nestjs'; import { AppService } from './app.service'; import { ExampleGuard } from './example.guard'; import { ExampleInterceptor } from './example.interceptor'; @@ -68,4 +69,9 @@ export class AppController { async killTestCron() { this.appService.killTestCron(); } + + @Get('flush') + async flush() { + await flush(); + } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts index ccc919cdd025..34e626cb8c52 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-basic/tests/errors.test.ts @@ -65,7 +65,7 @@ test('Does not send HttpExceptions to Sentry', async ({ baseURL }) => { await transactionEventPromise400; await transactionEventPromise500; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); @@ -90,7 +90,7 @@ test('Does not send RpcExceptions to Sentry', async ({ baseURL }) => { await transactionEventPromise; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts index 71a410e8d0a8..0d2c46e90da2 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/src/app.controller.ts @@ -1,4 +1,5 @@ import { Controller, Get, Param } from '@nestjs/common'; +import { flush } from '@sentry/nestjs'; import { AppService } from './app.service'; @Controller() @@ -14,4 +15,9 @@ export class AppController { async testExpectedException(@Param('id') id: string) { return this.appService.testExpectedException(id); } + + @Get('flush') + async flush() { + await flush(); + } } diff --git a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts index 87b828dc8501..6fbc9f2c1f32 100644 --- a/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/nestjs-with-submodules/tests/errors.test.ts @@ -81,7 +81,7 @@ test('Does not send exception to Sentry if user-defined global exception filter await transactionEventPromise; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); @@ -111,7 +111,7 @@ test('Does not send exception to Sentry if user-defined local exception filter a await transactionEventPromise; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts index 5becddbc05e0..ec0a921da2c4 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/src/app.controller.ts @@ -1,4 +1,5 @@ import { Controller, Get, Param, ParseIntPipe, UseGuards, UseInterceptors } from '@nestjs/common'; +import { flush } from '@sentry/nestjs'; import { AppService } from './app.service'; import { ExampleGuard } from './example.guard'; import { ExampleInterceptor } from './example.interceptor'; @@ -68,4 +69,9 @@ export class AppController { async killTestCron() { this.appService.killTestCron(); } + + @Get('flush') + async flush() { + await flush(); + } } diff --git a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts index 171f42920487..0155c3887805 100644 --- a/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts +++ b/dev-packages/e2e-tests/test-applications/node-nestjs-basic/tests/errors.test.ts @@ -65,7 +65,7 @@ test('Does not send HttpExceptions to Sentry', async ({ baseURL }) => { await transactionEventPromise400; await transactionEventPromise500; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); @@ -90,7 +90,7 @@ test('Does not send RpcExceptions to Sentry', async ({ baseURL }) => { await transactionEventPromise; - await new Promise(resolve => setTimeout(resolve, 10000)); + (await fetch(`${baseURL}/flush`)).text(); expect(errorEventOccurred).toBe(false); }); From d125ff28b8c4bc0d3a297d1eba452f569eb82774 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 6 Aug 2024 10:04:07 +0200 Subject: [PATCH 08/11] build(deps): bump nuxt from 3.11.2 to 3.12.4 in /dev-packages/e2e-tests/test-applications/nuxt-3 (#13242) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bumps [nuxt](https://github.com/nuxt/nuxt/tree/HEAD/packages/nuxt) from 3.11.2 to 3.12.4.
Release notes

Sourced from nuxt's releases.

v3.12.4

3.12.4 is the next regularly scheduled patch release.

👉 Changelog

compare changes

🔥 Performance

  • vite: Start warmups after nitro build (#27963)
  • vite: Avoid extra resolve call for resolveId in layers (#27971)
  • kit,nuxt,schema,vite,webpack: Use explicit exports (#27998)

🩹 Fixes

  • schema: Resolve public alias correctly (#27975)
  • nuxt: Omit rendering payload prefetch when noScripts (#27972)
  • nuxt: Add / as fallback if page can't be identified (e6109b226)
  • ui-templates: Validate templates with html-validate (#28024)
  • schema: Don't constrain postcss plugin options (#28045)
  • kit: Remove exports from v4 branch (5c8312e9b)
  • nuxt: Use unhead key for ad-hoc module options (#28088)
  • nuxt: Use native vue-router composables (#28114)
  • kit: Ensure getNuxtVersion returns string (#28125)
  • nuxt: Always prerender at least one page with crawler (#28131)
  • nuxt: Consider doc scroll-padding-top in scrollBehavior (#28083)
  • nuxt: Only warn when useAsyncData returns undefined (#28154)
  • nuxt: Revert change to getCachedData null response (d10cea11b)
  • schema: Don't use app/ as srcDir if it doesn't exist (#28176)
  • kit: Normalise serverDir within layers using v4 compat (#28177)
  • nuxt: Allow getCachedData to return undefined (#28187)
  • nuxt: Use addEventListener to register cookie store listener (#28193)
  • nuxt: Merge route meta properties with scanned meta (#28170)
  • nuxt: Prevent duplicate set-cookie headers (#28211)

💅 Refactors

  • schema,vite,webpack: Rework postcss module loading (#27946)
  • nuxt: Remove _registeredComponents from ssrContext (#27819)
  • nuxt: Use errx to handle dev log traces (#28027)

📖 Documentation

  • Fix link (83bd4fde9)
  • Fix Cloudflare spelling (#27989)
  • Update example to use nuxtApp.runWithContext (#28000)
  • Remove deprecated pending variable from data fetching docs (#28011)
  • Clarify xrsp danger (#28053)
  • Deprecate pending and emphasis undefined (#28113)
  • Update phrasing in route announcer (#28108)
  • Use code groups for install commands in module guide (#28094)
  • Capitalize text (#28056)
  • Mention content in upgrade guide v4 folder structure (#28090)
  • Remove a resolved issue from view transition docs (#28091)
  • Clarify navigateTo is not for nitro routes (#28092)
  • Warn about nested islands (#28062)

... (truncated)

Commits
  • 4a1349f v3.12.4
  • b7da949 fix(nuxt): prevent duplicate set-cookie headers (#28211)
  • 1843ffa refactor(nuxt): use errx to handle dev log traces (#28027)
  • 11264ad fix(nuxt): merge route meta properties with scanned meta (#28170)
  • 2417848 fix(nuxt): use addEventListener to register cookie store listener (#28193)
  • a6af09e fix(nuxt): allow getCachedData to return undefined (#28187)
  • d10cea1 fix(nuxt): revert change to getCachedData null response
  • e21f681 fix(nuxt): only warn when useAsyncData returns undefined (#28154)
  • 46a41ad chore(deps): update vitest to v2.0.3 (3.x) (#28153)
  • a2fd051 chore(deps): update all non-major dependencies (3.x) (#28058)
  • Additional commits viewable in compare view

[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=nuxt&package-manager=npm_and_yarn&previous-version=3.11.2&new-version=3.12.4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores) Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) ---
Dependabot commands and options
You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot squash and merge` will squash and merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge and block automerging - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually - `@dependabot show ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/getsentry/sentry-javascript/network/alerts).
Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- dev-packages/e2e-tests/test-applications/nuxt-3/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json index a487d61a144b..93471fff7aab 100644 --- a/dev-packages/e2e-tests/test-applications/nuxt-3/package.json +++ b/dev-packages/e2e-tests/test-applications/nuxt-3/package.json @@ -14,7 +14,7 @@ }, "dependencies": { "@sentry/nuxt": "latest || *", - "nuxt": "3.11.2" + "nuxt": "3.12.4" }, "devDependencies": { "@nuxt/test-utils": "^3.13.1", From ddff3029dd0a2c3d3cb4203b44c8bef8f05ba604 Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 6 Aug 2024 11:04:38 +0200 Subject: [PATCH 09/11] fix: Guard getReader function for other fetch implementations (#13246) --- packages/utils/src/instrument/fetch.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/utils/src/instrument/fetch.ts b/packages/utils/src/instrument/fetch.ts index afa209c01929..a161b8db79bb 100644 --- a/packages/utils/src/instrument/fetch.ts +++ b/packages/utils/src/instrument/fetch.ts @@ -116,7 +116,7 @@ function instrumentFetch(onFetchResolved?: (response: Response) => void, skipNat } async function resolveResponse(res: Response | undefined, onFinishedResolving: () => void): Promise { - if (res && res.body) { + if (res && res.body && res.body.getReader) { const responseReader = res.body.getReader(); // eslint-disable-next-line no-inner-declarations From 7fc479fb3a86c1c97e9b21f866586b53048f4dbc Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Tue, 6 Aug 2024 11:14:18 +0200 Subject: [PATCH 10/11] ref(core): Reduce `hasTracingEnabled` size (#13232) Inlining the function removes the function declaration from the bundle. --- packages/core/src/utils/hasTracingEnabled.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/core/src/utils/hasTracingEnabled.ts b/packages/core/src/utils/hasTracingEnabled.ts index 5e673bc08caa..9441a0fc7bed 100644 --- a/packages/core/src/utils/hasTracingEnabled.ts +++ b/packages/core/src/utils/hasTracingEnabled.ts @@ -16,12 +16,8 @@ export function hasTracingEnabled( return false; } - const options = maybeOptions || getClientOptions(); + const client = getClient(); + const options = maybeOptions || (client && client.getOptions()); // eslint-disable-next-line deprecation/deprecation return !!options && (options.enableTracing || 'tracesSampleRate' in options || 'tracesSampler' in options); } - -function getClientOptions(): Options | undefined { - const client = getClient(); - return client && client.getOptions(); -} From 7c7e2e255b328f20f9eb273d6603b40f823b7afe Mon Sep 17 00:00:00 2001 From: Charly Gomez Date: Tue, 6 Aug 2024 11:26:43 +0200 Subject: [PATCH 11/11] meta: Update changelog for 8.24.0 --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3eeb60765430..0ad5a1920aae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,12 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott +## 8.24.0 + +- feat(nestjs): Filter RPC exceptions (#13227) +- fix: Guard getReader function for other fetch implementations (#13246) +- fix(feedback): Ensure feedback can be lazy loaded in CDN bundles (#13241) + ## 8.23.0 ### Important Changes