From f05b4a1d99f3e6aa1b9a9dd259bee4fde0d98c4e Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 22 Mar 2024 11:31:46 +0100 Subject: [PATCH 01/39] build(bundles): Use ES2018 for bundles (#11201) closes https://github.com/getsentry/sentry-javascript/issues/9829 --- MIGRATION.md | 14 +++++++------- .../create-next-app/tsconfig.json | 2 +- .../create-react-app/tsconfig.json | 2 +- .../test-applications/generic-ts3.8/tsconfig.json | 4 ++-- .../test-applications/nextjs-14/tsconfig.json | 2 +- .../test-applications/nextjs-app-dir/tsconfig.json | 2 +- .../node-exports-test-app/tsconfig.json | 2 +- .../node-express-app/tsconfig.json | 2 +- .../react-create-hash-router/tsconfig.json | 2 +- .../react-router-6-use-routes/tsconfig.json | 2 +- .../standard-frontend-react/tsconfig.json | 2 +- dev-packages/rollup-utils/npmHelpers.mjs | 2 +- packages/angular/tsconfig.ngc.json | 4 ++-- packages/nextjs/test/integration/tsconfig.json | 2 +- packages/node-experimental/tsconfig.json | 2 +- packages/node/tsconfig.json | 2 +- packages/profiling-node/tsconfig.json | 2 +- packages/replay-worker/tsconfig.json | 2 +- packages/types/tsconfig.json | 2 +- packages/typescript/tsconfig.json | 4 ++-- yarn.lock | 2 ++ 21 files changed, 31 insertions(+), 29 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 1daf6c3d5c8d..f11ba0b59c42 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -24,18 +24,18 @@ stable release of `8.x` comes out). to `@sentry/node` and all of our node-based server-side sdks (`@sentry/nextjs`, `@sentry/serverless`, etc.). We no longer test against Node 8, 10, or 12 and cannot guarantee that the SDK will work as expected on these versions. -**Browser**: Our browser SDKs (`@sentry/browser`, `@sentry/react`, `@sentry/vue`, etc.) now require ES2017+ compatible +**Browser**: Our browser SDKs (`@sentry/browser`, `@sentry/react`, `@sentry/vue`, etc.) now require ES2018+ compatible browsers. This means that we no longer support IE11 (end of an era). This also means that the Browser SDK requires the fetch API to be available in the environment. New minimum supported browsers: -- Chrome 58 -- Edge 15 -- Safari/iOS Safari 11 -- Firefox 54 -- Opera 45 -- Samsung Internet 7.2 +- Chrome 63 +- Edge 79 +- Safari/iOS Safari 12 +- Firefox 58 +- Opera 50 +- Samsung Internet 8.2 For IE11 support please transpile your code to ES5 using babel or similar and add required polyfills. diff --git a/dev-packages/e2e-tests/test-applications/create-next-app/tsconfig.json b/dev-packages/e2e-tests/test-applications/create-next-app/tsconfig.json index 1fd2e9a8d510..73c09112c46a 100644 --- a/dev-packages/e2e-tests/test-applications/create-next-app/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/create-next-app/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/create-react-app/tsconfig.json b/dev-packages/e2e-tests/test-applications/create-react-app/tsconfig.json index bd19e4f07fc7..0e8eacbd8d09 100644 --- a/dev-packages/e2e-tests/test-applications/create-react-app/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/create-react-app/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/generic-ts3.8/tsconfig.json b/dev-packages/e2e-tests/test-applications/generic-ts3.8/tsconfig.json index ef27756e97d9..95de9c93fc38 100644 --- a/dev-packages/e2e-tests/test-applications/generic-ts3.8/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/generic-ts3.8/tsconfig.json @@ -1,11 +1,11 @@ { "include": ["index.ts"], "compilerOptions": { - "lib": ["es2017", "DOM"], + "lib": ["es2018", "DOM"], "skipLibCheck": false, "noEmit": true, "types": [], - "target": "es2017", + "target": "es2018", "moduleResolution": "node" } } diff --git a/dev-packages/e2e-tests/test-applications/nextjs-14/tsconfig.json b/dev-packages/e2e-tests/test-applications/nextjs-14/tsconfig.json index 6b81123d463c..f5a1f45a97e1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-14/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-14/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tsconfig.json b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tsconfig.json index 6b81123d463c..f5a1f45a97e1 100644 --- a/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/nextjs-app-dir/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/node-exports-test-app/tsconfig.json b/dev-packages/e2e-tests/test-applications/node-exports-test-app/tsconfig.json index 6f37f0817c4a..e1f37178feb7 100644 --- a/dev-packages/e2e-tests/test-applications/node-exports-test-app/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/node-exports-test-app/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "types": ["node"], "esModuleInterop": true, - "lib": ["es2017"], + "lib": ["es2018"], "strict": true, "outDir": "dist", "target": "ESNext", diff --git a/dev-packages/e2e-tests/test-applications/node-express-app/tsconfig.json b/dev-packages/e2e-tests/test-applications/node-express-app/tsconfig.json index d46ae8103211..8cb64e989ed9 100644 --- a/dev-packages/e2e-tests/test-applications/node-express-app/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/node-express-app/tsconfig.json @@ -2,7 +2,7 @@ "compilerOptions": { "types": ["node"], "esModuleInterop": true, - "lib": ["es2017"], + "lib": ["es2018"], "strict": true, "outDir": "dist" }, diff --git a/dev-packages/e2e-tests/test-applications/react-create-hash-router/tsconfig.json b/dev-packages/e2e-tests/test-applications/react-create-hash-router/tsconfig.json index 75ae036f46b0..4cc95dc2689a 100644 --- a/dev-packages/e2e-tests/test-applications/react-create-hash-router/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/react-create-hash-router/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/react-router-6-use-routes/tsconfig.json b/dev-packages/e2e-tests/test-applications/react-router-6-use-routes/tsconfig.json index 75ae036f46b0..4cc95dc2689a 100644 --- a/dev-packages/e2e-tests/test-applications/react-router-6-use-routes/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/react-router-6-use-routes/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json b/dev-packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json index 75ae036f46b0..4cc95dc2689a 100644 --- a/dev-packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json +++ b/dev-packages/e2e-tests/test-applications/standard-frontend-react/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es2017", + "target": "es2018", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, diff --git a/dev-packages/rollup-utils/npmHelpers.mjs b/dev-packages/rollup-utils/npmHelpers.mjs index 58bb4d75edf7..36ff6143936b 100644 --- a/dev-packages/rollup-utils/npmHelpers.mjs +++ b/dev-packages/rollup-utils/npmHelpers.mjs @@ -59,7 +59,7 @@ export function makeBaseNPMConfig(options = {}) { // output individual files rather than one big bundle preserveModules: true, - // Allow wrappers or helper functions generated by rollup to use any ES6 features except symbols. (Symbols in + // Allow wrappers or helper functions generated by rollup to use any ES2015 features except symbols. (Symbols in // general are fine, but the `[Symbol.toStringTag]: 'Module'` which Rollup adds alongside `__esModule: // true` in CJS modules makes it so that Jest <= 29.2.2 crashes when trying to mock generated `@sentry/xxx` // packages. See https://github.com/getsentry/sentry-javascript/pull/6043.) diff --git a/packages/angular/tsconfig.ngc.json b/packages/angular/tsconfig.ngc.json index 096ced563bba..e915bd8cc32c 100644 --- a/packages/angular/tsconfig.ngc.json +++ b/packages/angular/tsconfig.ngc.json @@ -5,9 +5,9 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "target": "es2017", + "target": "es2018", "declarationMap": false, - "lib": ["dom", "es2017"], + "lib": ["dom", "es2018"], "baseUrl": "./" }, "angularCompilerOptions": { diff --git a/packages/nextjs/test/integration/tsconfig.json b/packages/nextjs/test/integration/tsconfig.json index 49a874193c18..ed3ebdb2baea 100644 --- a/packages/nextjs/test/integration/tsconfig.json +++ b/packages/nextjs/test/integration/tsconfig.json @@ -7,7 +7,7 @@ "forceConsistentCasingInFileNames": true, "isolatedModules": true, "jsx": "preserve", - "lib": ["dom", "es2017"], + "lib": ["dom", "es2018"], "module": "esnext", "moduleResolution": "node", "noEmit": true, diff --git a/packages/node-experimental/tsconfig.json b/packages/node-experimental/tsconfig.json index 5a6bb72e5fd3..8f38d240197e 100644 --- a/packages/node-experimental/tsconfig.json +++ b/packages/node-experimental/tsconfig.json @@ -4,7 +4,7 @@ "include": ["src/**/*"], "compilerOptions": { - "lib": ["es2017"], + "lib": ["es2018"], "module": "Node16" } } diff --git a/packages/node/tsconfig.json b/packages/node/tsconfig.json index d38a5701a2bf..89a9b9e0e2fe 100644 --- a/packages/node/tsconfig.json +++ b/packages/node/tsconfig.json @@ -4,6 +4,6 @@ "include": ["src/**/*"], "compilerOptions": { - "lib": ["es2017"] + "lib": ["es2018"] } } diff --git a/packages/profiling-node/tsconfig.json b/packages/profiling-node/tsconfig.json index 03da9a484924..c53d22cf5270 100644 --- a/packages/profiling-node/tsconfig.json +++ b/packages/profiling-node/tsconfig.json @@ -2,7 +2,7 @@ "extends": "../../tsconfig.json", "compilerOptions": { "module": "esnext", - "lib": ["es2017"], + "lib": ["es2018"], "outDir": "lib", "types": ["node"] }, diff --git a/packages/replay-worker/tsconfig.json b/packages/replay-worker/tsconfig.json index dbacce80e01c..f3db9c003516 100644 --- a/packages/replay-worker/tsconfig.json +++ b/packages/replay-worker/tsconfig.json @@ -4,7 +4,7 @@ "module": "esnext", "lib": ["webworker", "scripthost"], "esModuleInterop": true, - "target": "es2017", + "target": "es2018", "strictPropertyInitialization": false }, "include": ["src/**/*.ts"] diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index d38a5701a2bf..89a9b9e0e2fe 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -4,6 +4,6 @@ "include": ["src/**/*"], "compilerOptions": { - "lib": ["es2017"] + "lib": ["es2018"] } } diff --git a/packages/typescript/tsconfig.json b/packages/typescript/tsconfig.json index 8f773bca55e3..d2457663e802 100644 --- a/packages/typescript/tsconfig.json +++ b/packages/typescript/tsconfig.json @@ -7,7 +7,7 @@ "importHelpers": true, "inlineSources": true, "isolatedModules": true, - "lib": ["es2017", "dom"], + "lib": ["es2018", "dom"], "moduleResolution": "node", "noErrorTruncation": true, "noFallthroughCasesInSwitch": true, @@ -19,6 +19,6 @@ "sourceMap": true, "strict": true, "strictBindCallApply": false, - "target": "es2017" + "target": "es2018" } } diff --git a/yarn.lock b/yarn.lock index 644e37903884..5064a198aea8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6713,6 +6713,7 @@ "@types/unist" "*" "@types/history-4@npm:@types/history@4.7.8", "@types/history-5@npm:@types/history@4.7.8", "@types/history@*": + name "@types/history-4" version "4.7.8" resolved "https://registry.yarnpkg.com/@types/history/-/history-4.7.8.tgz#49348387983075705fe8f4e02fb67f7daaec4934" integrity sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA== @@ -25288,6 +25289,7 @@ react-is@^18.0.0: "@remix-run/router" "1.0.2" "react-router-6@npm:react-router@6.3.0", react-router@6.3.0: + name react-router-6 version "6.3.0" resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.3.0.tgz#3970cc64b4cb4eae0c1ea5203a80334fdd175557" integrity sha512-7Wh1DzVQ+tlFjkeo+ujvjSqSJmkt1+8JO+T5xklPlgrh70y7ogx75ODRW0ThWhY7S+6yEDks8TYrtQe/aoboBQ== From 7c2f2b4afc760b31367d11c166f39aaab6546600 Mon Sep 17 00:00:00 2001 From: Lukas Stracke Date: Fri, 22 Mar 2024 12:15:08 +0100 Subject: [PATCH 02/39] fix(sveltekit): Ensure sub requests are recorded as child spans of parent request (#11130) When switching the SvelteKit server side SDK to `@sentry/node` powered by Otel, the semantics behind `continueTrace` changed as outlined in #11199. TLDR: We previously called `continueTrace` in a nested way when dealing with sub-requests`*` in SvelteKit. In our old Node SDK, this did nothing; in the new SDK, this currently causes a new root span/transaction to be created for the sub request. This patch now ensures that we continue to send sub request spans as child spans of the top-level/parent request. --- .../sveltekit-2/src/routes/+page.svelte | 3 + .../routes/server-load-fetch/+page.server.ts | 5 + .../src/routes/server-load-fetch/+page.svelte | 8 + .../test/performance.server.test.ts | 35 ++++ .../test-applications/sveltekit/package.json | 2 +- .../sveltekit/src/routes/+page.svelte | 3 + .../routes/server-load-fetch/+page.server.ts | 5 + .../src/routes/server-load-fetch/+page.svelte | 8 + .../sveltekit/test/performance.server.test.ts | 35 ++++ packages/sveltekit/src/server/handle.ts | 81 +++++----- packages/sveltekit/src/server/load.ts | 45 +++--- packages/sveltekit/test/server/handle.test.ts | 49 +++++- packages/sveltekit/test/server/load.test.ts | 152 +----------------- 13 files changed, 217 insertions(+), 214 deletions(-) create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.server.test.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.server.ts create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.svelte create mode 100644 dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte index 29ce9ec693a8..d8175182884a 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/+page.svelte @@ -26,4 +26,7 @@
  • Redirect
  • +
  • + Route with nested fetch in server load +
  • diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.server.ts new file mode 100644 index 000000000000..709e52bcf351 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.server.ts @@ -0,0 +1,5 @@ +export const load = async ({ fetch }) => { + const res = await fetch('/api/users'); + const data = await res.json(); + return { data }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.svelte new file mode 100644 index 000000000000..f7f814d31b4d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/src/routes/server-load-fetch/+page.svelte @@ -0,0 +1,8 @@ + + +
    +

    Server Load Fetch

    +

    {JSON.stringify(data, null, 2)}

    +
    diff --git a/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.server.test.ts new file mode 100644 index 000000000000..7aec23b30d7a --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit-2/test/performance.server.test.ts @@ -0,0 +1,35 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '../event-proxy-server'; + +test('server pageload request span has nested request span for sub request', async ({ page }) => { + const serverTxnEventPromise = waitForTransaction('sveltekit-2', txnEvent => { + return txnEvent?.transaction === 'GET /server-load-fetch'; + }); + + await page.goto('/server-load-fetch'); + + const serverTxnEvent = await serverTxnEventPromise; + const spans = serverTxnEvent.spans; + + expect(serverTxnEvent).toMatchObject({ + transaction: 'GET /server-load-fetch', + tags: { runtime: 'node' }, + transaction_info: { source: 'route' }, + type: 'transaction', + contexts: { + trace: { + op: 'http.server', + origin: 'auto.http.sveltekit', + }, + }, + }); + + expect(spans).toEqual( + expect.arrayContaining([ + // load span where the server load function initiates the sub request: + expect.objectContaining({ op: 'function.sveltekit.server.load', description: '/server-load-fetch' }), + // sub request span: + expect.objectContaining({ op: 'http.server', description: 'GET /api/users' }), + ]), + ); +}); diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/package.json b/dev-packages/e2e-tests/test-applications/sveltekit/package.json index c1ed602844c1..5a6b2d4d083c 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit/package.json +++ b/dev-packages/e2e-tests/test-applications/sveltekit/package.json @@ -22,7 +22,7 @@ "@sentry/utils": "latest || *", "@sveltejs/adapter-auto": "^2.0.0", "@sveltejs/adapter-node": "^1.2.4", - "@sveltejs/kit": "^1.30.3", + "@sveltejs/kit": "1.20.5", "svelte": "^3.54.0", "svelte-check": "^3.0.1", "ts-node": "10.9.1", diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/+page.svelte index aeb12d58603f..62dbf7856ab7 100644 --- a/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/+page.svelte +++ b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/+page.svelte @@ -23,4 +23,7 @@
  • Route with fetch in universal load
  • +
  • + Route with nested fetch in server load +
  • diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.server.ts b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.server.ts new file mode 100644 index 000000000000..709e52bcf351 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.server.ts @@ -0,0 +1,5 @@ +export const load = async ({ fetch }) => { + const res = await fetch('/api/users'); + const data = await res.json(); + return { data }; +}; diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.svelte b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.svelte new file mode 100644 index 000000000000..f7f814d31b4d --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit/src/routes/server-load-fetch/+page.svelte @@ -0,0 +1,8 @@ + + +
    +

    Server Load Fetch

    +

    {JSON.stringify(data, null, 2)}

    +
    diff --git a/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts b/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts new file mode 100644 index 000000000000..49fde5f01045 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/sveltekit/test/performance.server.test.ts @@ -0,0 +1,35 @@ +import { expect, test } from '@playwright/test'; +import { waitForTransaction } from '../event-proxy-server'; + +test('server pageload request span has nested request span for sub request', async ({ page }) => { + const serverTxnEventPromise = waitForTransaction('sveltekit', txnEvent => { + return txnEvent?.transaction === 'GET /server-load-fetch'; + }); + + await page.goto('/server-load-fetch'); + + const serverTxnEvent = await serverTxnEventPromise; + const spans = serverTxnEvent.spans; + + expect(serverTxnEvent).toMatchObject({ + transaction: 'GET /server-load-fetch', + tags: { runtime: 'node' }, + transaction_info: { source: 'route' }, + type: 'transaction', + contexts: { + trace: { + op: 'http.server', + origin: 'auto.http.sveltekit', + }, + }, + }); + + expect(spans).toEqual( + expect.arrayContaining([ + // load span where the server load function initiates the sub request: + expect.objectContaining({ op: 'function.sveltekit.server.load', description: '/server-load-fetch' }), + // sub request span: + expect.objectContaining({ op: 'http.server', description: 'GET /api/users' }), + ]), + ); +}); diff --git a/packages/sveltekit/src/server/handle.ts b/packages/sveltekit/src/server/handle.ts index 08ab880c5f27..0bb08be6ce50 100644 --- a/packages/sveltekit/src/server/handle.ts +++ b/packages/sveltekit/src/server/handle.ts @@ -149,15 +149,26 @@ export function sentryHandle(handlerOptions?: SentryHandleOptions): Handle { }; const sentryRequestHandler: Handle = input => { - // if there is an active span, we know that this handle call is nested and hence - // we don't create a new execution context for it. - // If we created one, nested server calls would create new root span instead - // of adding a child span to the currently active span. - if (getActiveSpan()) { + // event.isSubRequest was added in SvelteKit 1.21.0 and we can use it to check + // if we should create a new execution context or not. + // In case of a same-origin `fetch` call within a server`load` function, + // SvelteKit will actually just re-enter the `handle` function and set `isSubRequest` + // to `true` so that no additional network call is made. + // We want the `http.server` span of that nested call to be a child span of the + // currently active span instead of a new root span to correctly reflect this + // behavior. + // As a fallback for Kit < 1.21.0, we check if there is an active span only if there's none, + // we create a new execution context. + const isSubRequest = typeof input.event.isSubRequest === 'boolean' ? input.event.isSubRequest : !!getActiveSpan(); + + if (isSubRequest) { return instrumentHandle(input, options); } + return withIsolationScope(() => { - return instrumentHandle(input, options); + // We only call continueTrace in the initial top level request to avoid + // creating a new root span for the sub request. + return continueTrace(getTracePropagationData(input.event), () => instrumentHandle(input, options)); }); }; @@ -172,36 +183,32 @@ async function instrumentHandle( return resolve(event); } - const { sentryTrace, baggage } = getTracePropagationData(event); - - return continueTrace({ sentryTrace, baggage }, async () => { - try { - const resolveResult = await startSpan( - { - op: 'http.server', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url', - 'http.method': event.request.method, - }, - name: `${event.request.method} ${event.route?.id || event.url.pathname}`, - }, - async (span?: Span) => { - const res = await resolve(event, { - transformPageChunk: addSentryCodeToPage(options), - }); - if (span) { - setHttpStatus(span, res.status); - } - return res; + try { + const resolveResult = await startSpan( + { + op: 'http.server', + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.http.sveltekit', + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: event.route?.id ? 'route' : 'url', + 'http.method': event.request.method, }, - ); - return resolveResult; - } catch (e: unknown) { - sendErrorToSentry(e); - throw e; - } finally { - await flushIfServerless(); - } - }); + name: `${event.request.method} ${event.route?.id || event.url.pathname}`, + }, + async (span?: Span) => { + const res = await resolve(event, { + transformPageChunk: addSentryCodeToPage(options), + }); + if (span) { + setHttpStatus(span, res.status); + } + return res; + }, + ); + return resolveResult; + } catch (e: unknown) { + sendErrorToSentry(e); + throw e; + } finally { + await flushIfServerless(); + } } diff --git a/packages/sveltekit/src/server/load.ts b/packages/sveltekit/src/server/load.ts index d0d757c31ef6..fe61ed0913bd 100644 --- a/packages/sveltekit/src/server/load.ts +++ b/packages/sveltekit/src/server/load.ts @@ -2,7 +2,6 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, captureException, - continueTrace, startSpan, } from '@sentry/node'; import { addNonEnumerableProperty, objectify } from '@sentry/utils'; @@ -10,7 +9,7 @@ import type { LoadEvent, ServerLoadEvent } from '@sveltejs/kit'; import type { SentryWrappedFlag } from '../common/utils'; import { isHttpError, isRedirect } from '../common/utils'; -import { flushIfServerless, getTracePropagationData } from './utils'; +import { flushIfServerless } from './utils'; type PatchedLoadEvent = LoadEvent & SentryWrappedFlag; type PatchedServerLoadEvent = ServerLoadEvent & SentryWrappedFlag; @@ -132,30 +131,26 @@ export function wrapServerLoadWithSentry any>(origSe // https://github.com/sveltejs/kit/blob/e133aba479fa9ba0e7f9e71512f5f937f0247e2c/packages/kit/src/runtime/server/page/load_data.js#L111C3-L124 const routeId = event.route && (Object.getOwnPropertyDescriptor(event.route, 'id')?.value as string | undefined); - const { sentryTrace, baggage } = getTracePropagationData(event); - - return continueTrace({ sentryTrace, baggage }, async () => { - try { - // We need to await before returning, otherwise we won't catch any errors thrown by the load function - return await startSpan( - { - op: 'function.sveltekit.server.load', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url', - 'http.method': event.request.method, - }, - name: routeId ? routeId : event.url.pathname, + try { + // We need to await before returning, otherwise we won't catch any errors thrown by the load function + return await startSpan( + { + op: 'function.sveltekit.server.load', + attributes: { + [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit', + [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: routeId ? 'route' : 'url', + 'http.method': event.request.method, }, - () => wrappingTarget.apply(thisArg, args), - ); - } catch (e: unknown) { - sendErrorToSentry(e); - throw e; - } finally { - await flushIfServerless(); - } - }); + name: routeId ? routeId : event.url.pathname, + }, + () => wrappingTarget.apply(thisArg, args), + ); + } catch (e: unknown) { + sendErrorToSentry(e); + throw e; + } finally { + await flushIfServerless(); + } }, }); } diff --git a/packages/sveltekit/test/server/handle.test.ts b/packages/sveltekit/test/server/handle.test.ts index 1d720046fe48..2c3d1a9333f1 100644 --- a/packages/sveltekit/test/server/handle.test.ts +++ b/packages/sveltekit/test/server/handle.test.ts @@ -43,7 +43,6 @@ function mockEvent(override: Record = {}): Parameters[0 isDataRequest: false, ...override, - isSubRequest: false, }; return event; @@ -118,7 +117,6 @@ describe('sentryHandle', () => { response = await sentryHandle()({ event: mockEvent(), resolve: resolve(type, isError) }); } catch (e) { expect(e).toBeInstanceOf(Error); - // @ts-expect-error - this is fine expect(e.message).toEqual(type); } @@ -152,6 +150,53 @@ describe('sentryHandle', () => { expect(spans).toHaveLength(1); }); + it('[kit>=1.21.0] creates a child span for nested server calls (i.e. if there is an active span)', async () => { + let _span: Span | undefined = undefined; + let txnCount = 0; + client.on('spanEnd', span => { + if (span === getRootSpan(span)) { + _span = span; + ++txnCount; + } + }); + + try { + await sentryHandle()({ + event: mockEvent(), + resolve: async _ => { + // simulateing a nested load call: + await sentryHandle()({ + event: mockEvent({ route: { id: 'api/users/details/[id]', isSubRequest: true } }), + resolve: resolve(type, isError), + }); + return mockResponse; + }, + }); + } catch (e) { + // + } + + expect(txnCount).toEqual(1); + expect(_span!).toBeDefined(); + + expect(spanToJSON(_span!).description).toEqual('GET /users/[id]'); + expect(spanToJSON(_span!).op).toEqual('http.server'); + expect(spanToJSON(_span!).status).toEqual(isError ? 'internal_error' : 'ok'); + expect(spanToJSON(_span!).data?.[SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]).toEqual('route'); + + expect(spanToJSON(_span!).timestamp).toBeDefined(); + + const spans = getSpanDescendants(_span!).map(spanToJSON); + + expect(spans).toHaveLength(2); + expect(spans).toEqual( + expect.arrayContaining([ + expect.objectContaining({ op: 'http.server', description: 'GET /users/[id]' }), + expect.objectContaining({ op: 'http.server', description: 'GET api/users/details/[id]' }), + ]), + ); + }); + it('creates a child span for nested server calls (i.e. if there is an active span)', async () => { let _span: Span | undefined = undefined; let txnCount = 0; diff --git a/packages/sveltekit/test/server/load.test.ts b/packages/sveltekit/test/server/load.test.ts index d42615521e7a..699fcf034232 100644 --- a/packages/sveltekit/test/server/load.test.ts +++ b/packages/sveltekit/test/server/load.test.ts @@ -1,13 +1,12 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_OP, SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, - SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, addTracingExtensions, } from '@sentry/core'; import { NodeClient, getCurrentScope, getIsolationScope, setCurrentClient } from '@sentry/node'; import * as SentryNode from '@sentry/node'; -import type { Event, EventEnvelopeHeaders } from '@sentry/types'; +import type { Event } from '@sentry/types'; import type { Load, ServerLoad } from '@sveltejs/kit'; import { error, redirect } from '@sveltejs/kit'; import { vi } from 'vitest'; @@ -77,38 +76,6 @@ function getServerOnlyArgs() { }; } -function getServerArgsWithoutTracingHeaders() { - return { - ...getLoadArgs(), - request: { - method: 'GET', - headers: { - get: (_: string) => { - return null; - }, - }, - }, - }; -} - -function getServerArgsWithoutBaggageHeader() { - return { - ...getLoadArgs(), - request: { - method: 'GET', - headers: { - get: (key: string) => { - if (key === 'sentry-trace') { - return '1234567890abcdef1234567890abcdef-1234567890abcdef-1'; - } - - return null; - }, - }, - }, - }; -} - beforeAll(() => { addTracingExtensions(); }); @@ -281,119 +248,6 @@ describe('wrapServerLoadWithSentry calls `startSpan`', () => { mockCaptureException.mockClear(); }); - it('attaches trace data if available', async () => { - let envelopeHeaders: EventEnvelopeHeaders | undefined = undefined; - - client.on('beforeEnvelope', env => { - envelopeHeaders = env[0] as EventEnvelopeHeaders; - }); - - const wrappedLoad = wrapServerLoadWithSentry(serverLoad); - await wrappedLoad(getServerOnlyArgs()); - - await client.flush(); - - expect(txnEvents).toHaveLength(1); - const transaction = txnEvents[0]; - - expect(transaction.contexts?.trace).toEqual({ - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.sveltekit.server.load', - 'http.method': 'GET', - }, - op: 'function.sveltekit.server.load', - parent_span_id: '1234567890abcdef', - span_id: expect.any(String), - trace_id: '1234567890abcdef1234567890abcdef', - origin: 'auto.function.sveltekit', - }); - - expect(transaction.transaction).toEqual('/users/[id]'); - - expect(envelopeHeaders!.trace).toEqual({ - environment: 'production', - public_key: 'dogsarebadatkeepingsecrets', - release: '1.0.0', - sample_rate: '1', - trace_id: '1234567890abcdef1234567890abcdef', - transaction: 'dogpark', - }); - }); - - it("doesn't attach trace data if it's not available", async () => { - let envelopeHeaders: EventEnvelopeHeaders | undefined = undefined; - - client.on('beforeEnvelope', env => { - envelopeHeaders = env[0] as EventEnvelopeHeaders; - }); - - const wrappedLoad = wrapServerLoadWithSentry(serverLoad); - await wrappedLoad(getServerArgsWithoutTracingHeaders()); - - await client.flush(); - - expect(txnEvents).toHaveLength(1); - const transaction = txnEvents[0]; - - expect(transaction.contexts?.trace).toEqual({ - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.sveltekit.server.load', - [SEMANTIC_ATTRIBUTE_SENTRY_SAMPLE_RATE]: 1, - 'http.method': 'GET', - }, - op: 'function.sveltekit.server.load', - span_id: expect.any(String), - trace_id: expect.not.stringContaining('1234567890abcdef1234567890abcdef'), - origin: 'auto.function.sveltekit', - }); - expect(transaction.transaction).toEqual('/users/[id]'); - expect(envelopeHeaders!.trace).toEqual({ - environment: 'production', - public_key: 'public', - sample_rate: '1', - sampled: 'true', - release: '8.0.0', - trace_id: transaction.contexts?.trace?.trace_id, - transaction: '/users/[id]', - }); - }); - - it("doesn't attach the DSC data if the baggage header is not available", async () => { - let envelopeHeaders: EventEnvelopeHeaders | undefined = undefined; - - client.on('beforeEnvelope', env => { - envelopeHeaders = env[0] as EventEnvelopeHeaders; - }); - - const wrappedLoad = wrapServerLoadWithSentry(serverLoad); - await wrappedLoad(getServerArgsWithoutBaggageHeader()); - - await client.flush(); - - expect(txnEvents).toHaveLength(1); - const transaction = txnEvents[0]; - - expect(transaction.contexts?.trace).toEqual({ - data: { - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.function.sveltekit', - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'route', - [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.sveltekit.server.load', - 'http.method': 'GET', - }, - op: 'function.sveltekit.server.load', - parent_span_id: '1234567890abcdef', - span_id: expect.any(String), - trace_id: '1234567890abcdef1234567890abcdef', - origin: 'auto.function.sveltekit', - }); - expect(transaction.transaction).toEqual('/users/[id]'); - expect(envelopeHeaders!.trace).toEqual({}); - }); - it('falls back to the raw url if `event.route.id` is not available', async () => { const event = getServerOnlyArgs(); // @ts-expect-error - this is fine (just tests here) @@ -412,11 +266,11 @@ describe('wrapServerLoadWithSentry calls `startSpan`', () => { [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', [SEMANTIC_ATTRIBUTE_SENTRY_OP]: 'function.sveltekit.server.load', 'http.method': 'GET', + 'sentry.sample_rate': 1, }, op: 'function.sveltekit.server.load', - parent_span_id: '1234567890abcdef', span_id: expect.any(String), - trace_id: '1234567890abcdef1234567890abcdef', + trace_id: expect.any(String), origin: 'auto.function.sveltekit', }); expect(transaction.transaction).toEqual('/users/123'); From 28db5111dbb9f9d653318a240f15b42c51239d00 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Fri, 22 Mar 2024 13:03:38 +0000 Subject: [PATCH 03/39] fix(node): Local variables skipped after Promise (#11234) The debugger call stack does not include the `new Promise` frames that are parsed from `error.stack`. This means that when we go through the frames to apply the local variables, the frames don't match up and we bail. This patch ignores those frames when matching functions in the frames. --- .../LocalVariables/local-variables-caught.mjs | 14 ++++++++------ .../local-variables/local-variables-sync.ts | 16 +++++++++------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-caught.mjs b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-caught.mjs index a7427ac60157..8fec9dbb1dad 100644 --- a/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-caught.mjs +++ b/dev-packages/node-integration-tests/suites/public-api/LocalVariables/local-variables-caught.mjs @@ -9,12 +9,14 @@ Sentry.init({ }); class Some { - two(name) { - throw new Error('Enough!'); + async two(name) { + return new Promise((_, reject) => { + reject(new Error('Enough!')); + }); } } -function one(name) { +async function one(name) { const arr = [1, '2', null]; const obj = { name, @@ -30,12 +32,12 @@ function one(name) { const ty = new Some(); - ty.two(name); + await ty.two(name); } -setTimeout(() => { +setTimeout(async () => { try { - one('some name'); + await one('some name'); } catch (e) { Sentry.captureException(e); } diff --git a/packages/node-experimental/src/integrations/local-variables/local-variables-sync.ts b/packages/node-experimental/src/integrations/local-variables/local-variables-sync.ts index 111dc6d36c1e..91fb9005b4c3 100644 --- a/packages/node-experimental/src/integrations/local-variables/local-variables-sync.ts +++ b/packages/node-experimental/src/integrations/local-variables/local-variables-sync.ts @@ -288,14 +288,16 @@ const _localVariablesSyncIntegration = (( return; } - const frameCount = exception.stacktrace?.frames?.length || 0; + // Filter out frames where the function name is `new Promise` since these are in the error.stack frames + // but do not appear in the debugger call frames + const frames = (exception.stacktrace?.frames || []).filter(frame => frame.function !== 'new Promise'); - for (let i = 0; i < frameCount; i++) { + for (let i = 0; i < frames.length; i++) { // Sentry frames are in reverse order - const frameIndex = frameCount - i - 1; + const frameIndex = frames.length - i - 1; // Drop out if we run out of frames to match up - if (!exception?.stacktrace?.frames?.[frameIndex] || !cachedFrame[i]) { + if (!frames[frameIndex] || !cachedFrame[i]) { break; } @@ -303,14 +305,14 @@ const _localVariablesSyncIntegration = (( // We need to have vars to add cachedFrame[i].vars === undefined || // We're not interested in frames that are not in_app because the vars are not relevant - exception.stacktrace.frames[frameIndex].in_app === false || + frames[frameIndex].in_app === false || // The function names need to match - !functionNamesMatch(exception.stacktrace.frames[frameIndex].function, cachedFrame[i].function) + !functionNamesMatch(frames[frameIndex].function, cachedFrame[i].function) ) { continue; } - exception.stacktrace.frames[frameIndex].vars = cachedFrame[i].vars; + frames[frameIndex].vars = cachedFrame[i].vars; } } From 1c10b306f0ec045c4951963a098efc9ba74ae635 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Fri, 22 Mar 2024 14:23:39 +0100 Subject: [PATCH 04/39] ref(replay): Move `@sentry/replay` code to `@sentry-internal/replay` (#11200) closes https://github.com/getsentry/sentry-javascript/issues/9165 --- .craft.yml | 8 +- LICENSE | 2 +- MIGRATION.md | 8 + README.md | 4 +- .../suites/replay/bufferMode/test.ts | 4 +- .../captureReplayFromReplayPackage/init.js | 2 +- .../captureReplayFromReplayPackage/test.ts | 2 +- .../utils/generatePlugin.ts | 2 +- .../utils/replayHelpers.ts | 8 +- .../test-applications/generic-ts3.8/index.ts | 4 +- .../generic-ts3.8/package.json | 2 +- .../e2e-tests/verdaccio-config/config.yaml | 6 - package.json | 2 +- packages/browser/package.json | 2 +- packages/browser/rollup.bundle.config.mjs | 2 +- packages/browser/src/index.bundle.replay.ts | 2 +- .../index.bundle.tracing.replay.feedback.ts | 2 +- .../src/index.bundle.tracing.replay.ts | 2 +- packages/browser/src/index.ts | 4 +- packages/nextjs/test/integration/package.json | 2 +- packages/remix/test/integration/package.json | 2 +- packages/replay-canvas/CONTRIBUTING.md | 2 +- packages/replay-canvas/package.json | 2 +- packages/replay-canvas/src/canvas.ts | 2 +- .../{replay => replay-internal}/.eslintignore | 0 .../{replay => replay-internal}/.eslintrc.js | 0 .../{replay => replay-internal}/.gitignore | 0 .../CONTRIBUTING.md | 2 +- packages/{replay => replay-internal}/LICENSE | 0 .../{replay => replay-internal}/README.md | 11 +- .../jest.config.ts | 0 .../{replay => replay-internal}/jest.setup.ts | 0 .../{replay => replay-internal}/package.json | 2 +- .../rollup.bundle.config.mjs | 2 +- .../rollup.npm.config.mjs | 0 .../scripts/craft-pre-release.sh | 0 .../src/constants.ts | 0 .../src/coreHandlers/handleAfterSendEvent.ts | 0 .../src/coreHandlers/handleBeforeSendEvent.ts | 0 .../src/coreHandlers/handleBreadcrumbs.ts | 0 .../src/coreHandlers/handleClick.ts | 0 .../src/coreHandlers/handleDom.ts | 0 .../src/coreHandlers/handleGlobalEvent.ts | 0 .../src/coreHandlers/handleHistory.ts | 0 .../src/coreHandlers/handleKeyboardEvent.ts | 0 .../coreHandlers/handleNetworkBreadcrumbs.ts | 0 .../src/coreHandlers/performanceObserver.ts | 0 .../coreHandlers/util/addBreadcrumbEvent.ts | 0 .../util/addFeedbackBreadcrumb.ts | 0 .../coreHandlers/util/addNetworkBreadcrumb.ts | 0 .../src/coreHandlers/util/domUtils.ts | 0 .../src/coreHandlers/util/fetchUtils.ts | 0 .../util/getAttributesToRecord.ts | 0 .../src/coreHandlers/util/networkUtils.ts | 0 .../src/coreHandlers/util/onWindowOpen.ts | 0 .../util/shouldSampleForBufferEvent.ts | 0 .../src/coreHandlers/util/xhrUtils.ts | 0 .../src/debug-build.ts | 0 .../src/eventBuffer/EventBufferArray.ts | 0 .../EventBufferCompressionWorker.ts | 0 .../src/eventBuffer/EventBufferProxy.ts | 0 .../src/eventBuffer/WorkerHandler.ts | 0 .../src/eventBuffer/error.ts | 0 .../src/eventBuffer/index.ts | 0 .../{replay => replay-internal}/src/index.ts | 0 .../src/integration.ts | 0 .../{replay => replay-internal}/src/replay.ts | 0 .../src/session/Session.ts | 0 .../src/session/clearSession.ts | 0 .../src/session/createSession.ts | 0 .../src/session/fetchSession.ts | 0 .../src/session/index.ts | 0 .../src/session/loadOrCreateSession.ts | 0 .../src/session/saveSession.ts | 0 .../src/session/shouldRefreshSession.ts | 0 .../src/types/index.ts | 0 .../src/types/performance.ts | 0 .../src/types/replay.ts | 0 .../src/types/replayFrame.ts | 0 .../src/types/request.ts | 0 .../src/types/rrweb.ts | 0 .../src/util/addEvent.ts | 0 .../src/util/addGlobalListeners.ts | 0 .../src/util/addMemoryEntry.ts | 0 .../src/util/createBreadcrumb.ts | 0 .../src/util/createPerformanceEntries.ts | 0 .../src/util/createPerformanceSpans.ts | 0 .../src/util/createReplayEnvelope.ts | 0 .../src/util/debounce.ts | 0 .../src/util/eventUtils.ts | 0 .../src/util/getPrivacyOptions.ts | 0 .../src/util/getReplay.ts | 0 .../src/util/handleRecordingEmit.ts | 0 .../src/util/hasSessionStorage.ts | 0 .../src/util/isExpired.ts | 0 .../src/util/isRrwebError.ts | 0 .../src/util/isSampled.ts | 0 .../src/util/isSessionExpired.ts | 0 .../src/util/log.ts | 0 .../src/util/maskAttribute.ts | 0 .../src/util/prepareRecordingData.ts | 0 .../src/util/prepareReplayEvent.ts | 0 .../src/util/sendReplay.ts | 0 .../src/util/sendReplayRequest.ts | 0 .../src/util/shouldFilterRequest.ts | 0 .../src/util/throttle.ts | 0 .../src/util/timestamp.ts | 0 .../test/fixtures/error.ts | 0 .../test/fixtures/fixJson/1_completeJson.json | 0 .../fixtures/fixJson/1_incompleteJson.txt | 0 .../test/fixtures/fixJson/2_completeJson.json | 0 .../fixtures/fixJson/2_incompleteJson.txt | 0 .../fixtures/performanceEntry/navigation.ts | 0 .../fixtures/performanceEntry/resource.ts | 0 .../test/fixtures/transaction.ts | 0 .../{replay => replay-internal}/test/index.ts | 0 .../test/integration/autoSaveSession.test.ts | 0 .../beforeAddRecordingEvent.test.ts | 0 .../coreHandlers/handleAfterSendEvent.test.ts | 0 .../handleBeforeSendEvent.test.ts | 0 .../coreHandlers/handleGlobalEvent.test.ts | 0 .../test/integration/errorSampleRate.test.ts | 0 .../test/integration/eventProcessors.test.ts | 0 .../test/integration/events.test.ts | 0 .../test/integration/flush.test.ts | 0 .../test/integration/getReplayId.test.ts | 0 .../integration/integrationSettings.test.ts | 0 .../test/integration/rateLimiting.test.ts | 0 .../test/integration/rrweb.test.ts | 0 .../test/integration/sampling.test.ts | 0 .../test/integration/sendReplayEvent.test.ts | 0 .../test/integration/session.test.ts | 0 .../integration/shouldFilterRequest.test.ts | 0 .../test/integration/stop.test.ts | 0 .../test/mocks/mockRrweb.ts | 0 .../test/mocks/mockSdk.ts | 0 .../test/mocks/resetSdkMock.ts | 0 .../{replay => replay-internal}/test/types.ts | 0 .../coreHandlers/handleBreadcrumbs.test.ts | 0 .../unit/coreHandlers/handleClick.test.ts | 0 .../test/unit/coreHandlers/handleDom.test.ts | 0 .../coreHandlers/handleKeyboardEvent.test.ts | 0 .../handleNetworkBreadcrumbs.test.ts | 0 .../util/addBreadcrumbEvent.test.ts | 0 .../unit/coreHandlers/util/fetchUtils.test.ts | 0 .../util/getAttributesToRecord.test.ts | 0 .../coreHandlers/util/networkUtils.test.ts | 0 .../unit/coreHandlers/util/xhrUtils.test.ts | 0 .../unit/eventBuffer/EventBufferArray.test.ts | 0 .../EventBufferCompressionWorker.test.ts | 0 .../unit/eventBuffer/EventBufferProxy.test.ts | 0 .../test/unit/multipleInstances.test.ts | 0 .../test/unit/session/createSession.test.ts | 0 .../test/unit/session/fetchSession.test.ts | 0 .../unit/session/loadOrCreateSession.test.ts | 0 .../test/unit/session/saveSession.test.ts | 0 .../test/unit/session/sessionSampling.test.ts | 0 .../test/unit/util/addEvent.test.ts | 0 .../unit/util/createPerformanceEntry.test.ts | 0 .../unit/util/createReplayEnvelope.test.ts | 0 .../test/unit/util/debounce.test.ts | 0 .../test/unit/util/getPrivacyOptions.test.ts | 0 .../test/unit/util/getReplay.test.ts | 0 .../unit/util/handleRecordingEmit.test.ts | 0 .../test/unit/util/isExpired.test.ts | 0 .../test/unit/util/isSampled.test.ts | 0 .../test/unit/util/isSessionExpired.test.ts | 0 .../test/unit/util/maskAttribute.test.ts | 0 .../test/unit/util/prepareReplayEvent.test.ts | 0 .../test/unit/util/throttle.test.ts | 0 .../test/utils/TestClient.ts | 0 .../test/utils/compression.ts | 0 .../test/utils/getTestEvent.ts | 0 .../test/utils/setupReplayContainer.ts | 0 .../test/utils/use-fake-timers.ts | 0 .../{replay => replay-internal}/tsconfig.json | 0 .../tsconfig.test.json | 0 .../tsconfig.types.json | 0 packages/replay-worker/README.md | 4 +- packages/replay-worker/package.json | 2 +- packages/replay/MIGRATION.md | 156 ------------------ scripts/node-unit-tests.ts | 2 +- 182 files changed, 54 insertions(+), 205 deletions(-) rename packages/{replay => replay-internal}/.eslintignore (100%) rename packages/{replay => replay-internal}/.eslintrc.js (100%) rename packages/{replay => replay-internal}/.gitignore (100%) rename packages/{replay => replay-internal}/CONTRIBUTING.md (59%) rename packages/{replay => replay-internal}/LICENSE (100%) rename packages/{replay => replay-internal}/README.md (96%) rename packages/{replay => replay-internal}/jest.config.ts (100%) rename packages/{replay => replay-internal}/jest.setup.ts (100%) rename packages/{replay => replay-internal}/package.json (98%) rename packages/{replay => replay-internal}/rollup.bundle.config.mjs (88%) rename packages/{replay => replay-internal}/rollup.npm.config.mjs (100%) rename packages/{replay => replay-internal}/scripts/craft-pre-release.sh (100%) rename packages/{replay => replay-internal}/src/constants.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleAfterSendEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleBeforeSendEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleBreadcrumbs.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleClick.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleDom.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleGlobalEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleHistory.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleKeyboardEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/handleNetworkBreadcrumbs.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/performanceObserver.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/addBreadcrumbEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/addFeedbackBreadcrumb.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/addNetworkBreadcrumb.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/domUtils.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/fetchUtils.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/getAttributesToRecord.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/networkUtils.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/onWindowOpen.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/shouldSampleForBufferEvent.ts (100%) rename packages/{replay => replay-internal}/src/coreHandlers/util/xhrUtils.ts (100%) rename packages/{replay => replay-internal}/src/debug-build.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/EventBufferArray.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/EventBufferCompressionWorker.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/EventBufferProxy.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/WorkerHandler.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/error.ts (100%) rename packages/{replay => replay-internal}/src/eventBuffer/index.ts (100%) rename packages/{replay => replay-internal}/src/index.ts (100%) rename packages/{replay => replay-internal}/src/integration.ts (100%) rename packages/{replay => replay-internal}/src/replay.ts (100%) rename packages/{replay => replay-internal}/src/session/Session.ts (100%) rename packages/{replay => replay-internal}/src/session/clearSession.ts (100%) rename packages/{replay => replay-internal}/src/session/createSession.ts (100%) rename packages/{replay => replay-internal}/src/session/fetchSession.ts (100%) rename packages/{replay => replay-internal}/src/session/index.ts (100%) rename packages/{replay => replay-internal}/src/session/loadOrCreateSession.ts (100%) rename packages/{replay => replay-internal}/src/session/saveSession.ts (100%) rename packages/{replay => replay-internal}/src/session/shouldRefreshSession.ts (100%) rename packages/{replay => replay-internal}/src/types/index.ts (100%) rename packages/{replay => replay-internal}/src/types/performance.ts (100%) rename packages/{replay => replay-internal}/src/types/replay.ts (100%) rename packages/{replay => replay-internal}/src/types/replayFrame.ts (100%) rename packages/{replay => replay-internal}/src/types/request.ts (100%) rename packages/{replay => replay-internal}/src/types/rrweb.ts (100%) rename packages/{replay => replay-internal}/src/util/addEvent.ts (100%) rename packages/{replay => replay-internal}/src/util/addGlobalListeners.ts (100%) rename packages/{replay => replay-internal}/src/util/addMemoryEntry.ts (100%) rename packages/{replay => replay-internal}/src/util/createBreadcrumb.ts (100%) rename packages/{replay => replay-internal}/src/util/createPerformanceEntries.ts (100%) rename packages/{replay => replay-internal}/src/util/createPerformanceSpans.ts (100%) rename packages/{replay => replay-internal}/src/util/createReplayEnvelope.ts (100%) rename packages/{replay => replay-internal}/src/util/debounce.ts (100%) rename packages/{replay => replay-internal}/src/util/eventUtils.ts (100%) rename packages/{replay => replay-internal}/src/util/getPrivacyOptions.ts (100%) rename packages/{replay => replay-internal}/src/util/getReplay.ts (100%) rename packages/{replay => replay-internal}/src/util/handleRecordingEmit.ts (100%) rename packages/{replay => replay-internal}/src/util/hasSessionStorage.ts (100%) rename packages/{replay => replay-internal}/src/util/isExpired.ts (100%) rename packages/{replay => replay-internal}/src/util/isRrwebError.ts (100%) rename packages/{replay => replay-internal}/src/util/isSampled.ts (100%) rename packages/{replay => replay-internal}/src/util/isSessionExpired.ts (100%) rename packages/{replay => replay-internal}/src/util/log.ts (100%) rename packages/{replay => replay-internal}/src/util/maskAttribute.ts (100%) rename packages/{replay => replay-internal}/src/util/prepareRecordingData.ts (100%) rename packages/{replay => replay-internal}/src/util/prepareReplayEvent.ts (100%) rename packages/{replay => replay-internal}/src/util/sendReplay.ts (100%) rename packages/{replay => replay-internal}/src/util/sendReplayRequest.ts (100%) rename packages/{replay => replay-internal}/src/util/shouldFilterRequest.ts (100%) rename packages/{replay => replay-internal}/src/util/throttle.ts (100%) rename packages/{replay => replay-internal}/src/util/timestamp.ts (100%) rename packages/{replay => replay-internal}/test/fixtures/error.ts (100%) rename packages/{replay => replay-internal}/test/fixtures/fixJson/1_completeJson.json (100%) rename packages/{replay => replay-internal}/test/fixtures/fixJson/1_incompleteJson.txt (100%) rename packages/{replay => replay-internal}/test/fixtures/fixJson/2_completeJson.json (100%) rename packages/{replay => replay-internal}/test/fixtures/fixJson/2_incompleteJson.txt (100%) rename packages/{replay => replay-internal}/test/fixtures/performanceEntry/navigation.ts (100%) rename packages/{replay => replay-internal}/test/fixtures/performanceEntry/resource.ts (100%) rename packages/{replay => replay-internal}/test/fixtures/transaction.ts (100%) rename packages/{replay => replay-internal}/test/index.ts (100%) rename packages/{replay => replay-internal}/test/integration/autoSaveSession.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/beforeAddRecordingEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/coreHandlers/handleAfterSendEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/coreHandlers/handleBeforeSendEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/coreHandlers/handleGlobalEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/errorSampleRate.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/eventProcessors.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/events.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/flush.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/getReplayId.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/integrationSettings.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/rateLimiting.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/rrweb.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/sampling.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/sendReplayEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/session.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/shouldFilterRequest.test.ts (100%) rename packages/{replay => replay-internal}/test/integration/stop.test.ts (100%) rename packages/{replay => replay-internal}/test/mocks/mockRrweb.ts (100%) rename packages/{replay => replay-internal}/test/mocks/mockSdk.ts (100%) rename packages/{replay => replay-internal}/test/mocks/resetSdkMock.ts (100%) rename packages/{replay => replay-internal}/test/types.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/handleBreadcrumbs.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/handleClick.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/handleDom.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/handleKeyboardEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/util/fetchUtils.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/util/getAttributesToRecord.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/util/networkUtils.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/coreHandlers/util/xhrUtils.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/eventBuffer/EventBufferArray.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/eventBuffer/EventBufferCompressionWorker.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/eventBuffer/EventBufferProxy.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/multipleInstances.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/session/createSession.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/session/fetchSession.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/session/loadOrCreateSession.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/session/saveSession.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/session/sessionSampling.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/addEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/createPerformanceEntry.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/createReplayEnvelope.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/debounce.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/getPrivacyOptions.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/getReplay.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/handleRecordingEmit.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/isExpired.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/isSampled.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/isSessionExpired.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/maskAttribute.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/prepareReplayEvent.test.ts (100%) rename packages/{replay => replay-internal}/test/unit/util/throttle.test.ts (100%) rename packages/{replay => replay-internal}/test/utils/TestClient.ts (100%) rename packages/{replay => replay-internal}/test/utils/compression.ts (100%) rename packages/{replay => replay-internal}/test/utils/getTestEvent.ts (100%) rename packages/{replay => replay-internal}/test/utils/setupReplayContainer.ts (100%) rename packages/{replay => replay-internal}/test/utils/use-fake-timers.ts (100%) rename packages/{replay => replay-internal}/tsconfig.json (100%) rename packages/{replay => replay-internal}/tsconfig.test.json (100%) rename packages/{replay => replay-internal}/tsconfig.types.json (100%) delete mode 100644 packages/replay/MIGRATION.md diff --git a/.craft.yml b/.craft.yml index f0db51dc1582..27ff96e235d9 100644 --- a/.craft.yml +++ b/.craft.yml @@ -20,11 +20,11 @@ targets: - name: npm id: '@sentry-internal/tracing' includeNames: /^sentry-internal-tracing-\d.*\.tgz$/ - ## 1.5 Replay package (browser only) + ## 1.5 Replay Internal package (browser only) - name: npm - id: '@sentry/replay' - includeNames: /^sentry-replay-\d.*\.tgz$/ - ## 1.6. OpenTelemetry package + id: '@sentry-internal/replay' + includeNames: /^sentry-internal-replay-\d.*\.tgz$/ + ## 1.6 OpenTelemetry package - name: npm id: '@sentry/opentelemetry' includeNames: /^sentry-opentelemetry-\d.*\.tgz$/ diff --git a/LICENSE b/LICENSE index 293314012679..63e7eb28e19c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2022 Functional Software, Inc. dba Sentry +Copyright (c) 2024 Functional Software, Inc. dba Sentry Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in diff --git a/MIGRATION.md b/MIGRATION.md index f11ba0b59c42..e95de8d8be29 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -577,6 +577,8 @@ Removed top-level exports: `Offline`, `makeXHRTransport`, `BrowserTracing`, `wra - [Removal of Offline integration](./MIGRATION.md#removal-of-the-offline-integration) - [Removal of `makeXHRTransport` transport](./MIGRATION.md#removal-of-makexhrtransport-transport) - [Removal of `wrap` method](./MIGRATION.md#removal-of-wrap-method) +- [Removal of `@sentry/angular-ivy` package](./MIGRATION.md#removal-of-sentryangular-ivy-package) +- [Removal of `@sentry/replay` package](./MIGRATION.md#removal-of-sentryreplay-package) #### Removal of the `BrowserTracing` integration @@ -605,6 +607,10 @@ requires at least Angular 14. If you are using Angular 13 or lower, we suggest u migrating to v8. If you can't upgrade your Angular version to at least Angular 14, you can also continue using the `@sentry/angular-ivy@7` SDK. However, v7 of the SDKs will no longer be fully supported going forward. +#### Removal of `@sentry/replay` package + +You can import from `@sentry/browser` (or from a respective SDK package like `@sentry/react` or `@sentry/vue`). + ### Server-side SDKs (Node, Deno, Bun, etc.) Removed top-level exports: `enableAnrDetection`, `Anr`, `deepReadDirSync` @@ -907,6 +913,8 @@ SDK. - [Updated behaviour of `transactionContext` passed to `tracesSampler`](./MIGRATION.md#transactioncontext-no-longer-passed-to-tracessampler) - [Updated behaviour of `getClient()`](./MIGRATION.md#getclient-always-returns-a-client) - [Removal of Client-Side health check transaction filters](./MIGRATION.md#removal-of-client-side-health-check-transaction-filters) +- [Change of Replay default options (`unblock` and `unmask`)](./MIGRATION.md#change-of-replay-default-options-unblock-and-unmask) +- [Angular Tracing Decorator renaming](./MIGRATION.md#angular-tracing-decorator-renaming) #### Updated behaviour of `tracePropagationTargets` in the browser (HTTP tracing headers & CORS) diff --git a/README.md b/README.md index ff367a2018d5..101b712ced0b 100644 --- a/README.md +++ b/README.md @@ -93,8 +93,8 @@ Besides the high-level SDKs, this repository contains shared packages, helpers a development. If you're thinking about contributing to or creating a JavaScript-based SDK, have a look at the resources below: -- [`@sentry/replay`](https://github.com/getsentry/sentry-javascript/tree/master/packages/replay): Provides the - integration for Session Replay. +- [`@sentry-internal/replay`](https://github.com/getsentry/sentry-javascript/tree/master/packages/replay-internal): + Provides the integration for Session Replay. - [`@sentry/core`](https://github.com/getsentry/sentry-javascript/tree/master/packages/core): The base for all JavaScript SDKs with interfaces, type definitions and base classes. - [`@sentry/utils`](https://github.com/getsentry/sentry-javascript/tree/master/packages/utils): A set of helpers and diff --git a/dev-packages/browser-integration-tests/suites/replay/bufferMode/test.ts b/dev-packages/browser-integration-tests/suites/replay/bufferMode/test.ts index 9c10b6777d67..09fc602d92b7 100644 --- a/dev-packages/browser-integration-tests/suites/replay/bufferMode/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/bufferMode/test.ts @@ -1,6 +1,6 @@ import { expect } from '@playwright/test'; -import type { replayIntegration as actualReplayIntegration } from '@sentry/replay'; -import type { ReplayContainer } from '@sentry/replay/build/npm/types/types'; +import type { replayIntegration as actualReplayIntegration } from '@sentry-internal/replay'; +import type { ReplayContainer } from '@sentry-internal/replay/build/npm/types/types'; import { sentryTest } from '../../../utils/fixtures'; import { envelopeRequestParser, waitForErrorRequest } from '../../../utils/helpers'; diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/init.js b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/init.js index f71ddfdaaa9b..659e7b4618b2 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/init.js +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/init.js @@ -1,5 +1,5 @@ +import { replayIntegration } from '@sentry-internal/replay'; import * as Sentry from '@sentry/browser'; -import { replayIntegration } from '@sentry/replay'; window.Sentry = Sentry; window.Replay = replayIntegration({ diff --git a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts index 2235853ab5cc..58260c4c577f 100644 --- a/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/captureReplayFromReplayPackage/test.ts @@ -4,7 +4,7 @@ import { SDK_VERSION } from '@sentry/browser'; import { sentryTest } from '../../../utils/fixtures'; import { getReplayEvent, shouldSkipReplayTest, waitForReplayRequest } from '../../../utils/replayHelpers'; -sentryTest('should capture replays (@sentry/replay export)', async ({ getLocalTestPath, page }) => { +sentryTest('should capture replays (@sentry-internal/replay export)', async ({ getLocalTestPath, page }) => { if (shouldSkipReplayTest()) { sentryTest.skip(); } diff --git a/dev-packages/browser-integration-tests/utils/generatePlugin.ts b/dev-packages/browser-integration-tests/utils/generatePlugin.ts index f3875c561e74..d2907ae47af1 100644 --- a/dev-packages/browser-integration-tests/utils/generatePlugin.ts +++ b/dev-packages/browser-integration-tests/utils/generatePlugin.ts @@ -162,7 +162,7 @@ class SentryScenarioGenerationPlugin { ? { // To help Webpack resolve Sentry modules in `import` statements in cases where they're provided in bundles rather than in `node_modules` '@sentry/browser': 'Sentry', - '@sentry/replay': 'Sentry', + '@sentry-internal/replay': 'Sentry', '@sentry/wasm': 'Sentry', } : {}; diff --git a/dev-packages/browser-integration-tests/utils/replayHelpers.ts b/dev-packages/browser-integration-tests/utils/replayHelpers.ts index f0015d2dfb7f..36727664dce3 100644 --- a/dev-packages/browser-integration-tests/utils/replayHelpers.ts +++ b/dev-packages/browser-integration-tests/utils/replayHelpers.ts @@ -1,16 +1,16 @@ import type { Page, Request, Response } from '@playwright/test'; /* eslint-disable max-lines */ import type { ReplayCanvasIntegrationOptions } from '@sentry-internal/replay-canvas'; -import type { fullSnapshotEvent, incrementalSnapshotEvent } from '@sentry-internal/rrweb'; -import { EventType } from '@sentry-internal/rrweb'; -import type { ReplayEventWithTime } from '@sentry/browser'; import type { InternalEventContext, RecordingEvent, ReplayContainer, ReplayPluginOptions, Session, -} from '@sentry/replay/build/npm/types/types'; +} from '@sentry-internal/replay/build/npm/types/types'; +import type { fullSnapshotEvent, incrementalSnapshotEvent } from '@sentry-internal/rrweb'; +import { EventType } from '@sentry-internal/rrweb'; +import type { ReplayEventWithTime } from '@sentry/browser'; import type { Breadcrumb, Event, ReplayEvent, ReplayRecordingMode } from '@sentry/types'; import pako from 'pako'; diff --git a/dev-packages/e2e-tests/test-applications/generic-ts3.8/index.ts b/dev-packages/e2e-tests/test-applications/generic-ts3.8/index.ts index 241d82f715a0..0a78073e88ae 100644 --- a/dev-packages/e2e-tests/test-applications/generic-ts3.8/index.ts +++ b/dev-packages/e2e-tests/test-applications/generic-ts3.8/index.ts @@ -1,3 +1,5 @@ +// biome-ignore lint/nursery/noUnusedImports: +import * as _SentryReplay from '@sentry-internal/replay'; // biome-ignore lint/nursery/noUnusedImports: we need to import the SDK to ensure tsc check the types import * as _SentryBrowser from '@sentry/browser'; // biome-ignore lint/nursery/noUnusedImports: @@ -5,8 +7,6 @@ import * as _SentryCore from '@sentry/core'; // biome-ignore lint/nursery/noUnusedImports: import * as _SentryNode from '@sentry/node'; // biome-ignore lint/nursery/noUnusedImports: -import * as _SentryReplay from '@sentry/replay'; -// biome-ignore lint/nursery/noUnusedImports: import * as _SentryTypes from '@sentry/types'; // biome-ignore lint/nursery/noUnusedImports: import * as _SentryUtils from '@sentry/utils'; 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 acaa0a116ac0..d13bf86e7c64 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 @@ -16,7 +16,7 @@ "@sentry/browser": "latest || *", "@sentry/core": "latest || *", "@sentry/node": "latest || *", - "@sentry/replay": "latest || *", + "@sentry-internal/replay": "latest || *", "@sentry/types": "latest || *", "@sentry/utils": "latest || *", "@sentry/wasm": "latest || *" diff --git a/dev-packages/e2e-tests/verdaccio-config/config.yaml b/dev-packages/e2e-tests/verdaccio-config/config.yaml index 0fb3e645d81f..2cb28f875977 100644 --- a/dev-packages/e2e-tests/verdaccio-config/config.yaml +++ b/dev-packages/e2e-tests/verdaccio-config/config.yaml @@ -122,12 +122,6 @@ packages: unpublish: $all # proxy: npmjs # Don't proxy for E2E tests! - '@sentry/replay': - access: $all - publish: $all - unpublish: $all - # proxy: npmjs # Don't proxy for E2E tests! - '@sentry/aws-serverless': access: $all publish: $all diff --git a/package.json b/package.json index 3bb2bd8b6c12..1b2ad37340ea 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "packages/profiling-node", "packages/react", "packages/remix", - "packages/replay", + "packages/replay-internal", "packages/replay-canvas", "packages/replay-worker", "packages/svelte", diff --git a/packages/browser/package.json b/packages/browser/package.json index fe09ba59d12e..9158e1f21d04 100644 --- a/packages/browser/package.json +++ b/packages/browser/package.json @@ -43,10 +43,10 @@ }, "dependencies": { "@sentry-internal/feedback": "8.0.0-alpha.4", + "@sentry-internal/replay": "8.0.0-alpha.4", "@sentry-internal/replay-canvas": "8.0.0-alpha.4", "@sentry-internal/tracing": "8.0.0-alpha.4", "@sentry/core": "8.0.0-alpha.4", - "@sentry/replay": "8.0.0-alpha.4", "@sentry/types": "8.0.0-alpha.4", "@sentry/utils": "8.0.0-alpha.4" }, diff --git a/packages/browser/rollup.bundle.config.mjs b/packages/browser/rollup.bundle.config.mjs index 7ebddd4e2f04..16c769582050 100644 --- a/packages/browser/rollup.bundle.config.mjs +++ b/packages/browser/rollup.bundle.config.mjs @@ -52,7 +52,7 @@ const tracingBaseBundleConfig = makeBaseBundleConfig({ const replayBaseBundleConfig = makeBaseBundleConfig({ bundleType: 'standalone', entrypoints: ['src/index.bundle.replay.ts'], - licenseTitle: '@sentry/browser & @sentry/replay', + licenseTitle: '@sentry/browser (Replay)', outputFileBase: () => 'bundles/bundle.replay', }); diff --git a/packages/browser/src/index.bundle.replay.ts b/packages/browser/src/index.bundle.replay.ts index 29bf0b320dea..ec0a50c92905 100644 --- a/packages/browser/src/index.bundle.replay.ts +++ b/packages/browser/src/index.bundle.replay.ts @@ -4,7 +4,7 @@ import { browserTracingIntegrationShim, feedbackIntegrationShim, } from '@sentry-internal/integration-shims'; -import { replayIntegration } from '@sentry/replay'; +import { replayIntegration } from '@sentry-internal/replay'; export * from './index.bundle.base'; export { diff --git a/packages/browser/src/index.bundle.tracing.replay.feedback.ts b/packages/browser/src/index.bundle.tracing.replay.feedback.ts index 1fe669f2393f..48064ca051bd 100644 --- a/packages/browser/src/index.bundle.tracing.replay.feedback.ts +++ b/packages/browser/src/index.bundle.tracing.replay.feedback.ts @@ -1,7 +1,7 @@ import { feedbackIntegration } from '@sentry-internal/feedback'; +import { replayIntegration } from '@sentry-internal/replay'; import { browserTracingIntegration } from '@sentry-internal/tracing'; import { addTracingExtensions } from '@sentry/core'; -import { replayIntegration } from '@sentry/replay'; // We are patching the global object with our hub extension methods addTracingExtensions(); diff --git a/packages/browser/src/index.bundle.tracing.replay.ts b/packages/browser/src/index.bundle.tracing.replay.ts index 7b09054540b8..52d082dd3438 100644 --- a/packages/browser/src/index.bundle.tracing.replay.ts +++ b/packages/browser/src/index.bundle.tracing.replay.ts @@ -1,7 +1,7 @@ import { feedbackIntegrationShim } from '@sentry-internal/integration-shims'; +import { replayIntegration } from '@sentry-internal/replay'; import { browserTracingIntegration } from '@sentry-internal/tracing'; import { addTracingExtensions } from '@sentry/core'; -import { replayIntegration } from '@sentry/replay'; // We are patching the global object with our hub extension methods addTracingExtensions(); diff --git a/packages/browser/src/index.ts b/packages/browser/src/index.ts index 4b5248f91683..66ea45739489 100644 --- a/packages/browser/src/index.ts +++ b/packages/browser/src/index.ts @@ -32,7 +32,7 @@ export { export { replayIntegration, getReplay, -} from '@sentry/replay'; +} from '@sentry-internal/replay'; export type { ReplayEventType, ReplayEventWithTime, @@ -43,7 +43,7 @@ export type { ReplayFrameEvent, ReplaySpanFrame, ReplaySpanFrameEvent, -} from '@sentry/replay'; +} from '@sentry-internal/replay'; export { replayCanvasIntegration } from '@sentry-internal/replay-canvas'; diff --git a/packages/nextjs/test/integration/package.json b/packages/nextjs/test/integration/package.json index afb23b2fb6f4..dc2f84c2a85b 100644 --- a/packages/nextjs/test/integration/package.json +++ b/packages/nextjs/test/integration/package.json @@ -31,7 +31,7 @@ "@sentry/node-experimental": "file:../../../node", "@sentry/opentelemetry": "file:../../../opentelemetry", "@sentry/react": "file:../../../react", - "@sentry/replay": "file:../../../replay", + "@sentry-internal/replay": "file:../../../replay-internal", "@sentry-internal/replay-canvas": "file:../../../replay-canvas", "@sentry-internal/tracing": "file:../../../tracing-internal", "@sentry-internal/feedback": "file:../../../feedback", diff --git a/packages/remix/test/integration/package.json b/packages/remix/test/integration/package.json index 3d7cb377a74b..e5a763551fe9 100644 --- a/packages/remix/test/integration/package.json +++ b/packages/remix/test/integration/package.json @@ -28,7 +28,7 @@ "@sentry/node": "file:../../../node-experimental", "@sentry/opentelemetry": "file:../../../opentelemetry", "@sentry/react": "file:../../../react", - "@sentry/replay": "file:../../../replay", + "@sentry-internal/replay": "file:../../../replay-internal", "@sentry-internal/replay-canvas": "file:../../../replay-canvas", "@sentry-internal/tracing": "file:../../../tracing-internal", "@sentry-internal/feedback": "file:../../../feedback", diff --git a/packages/replay-canvas/CONTRIBUTING.md b/packages/replay-canvas/CONTRIBUTING.md index 7b4a70f075ab..b82dc89e3d70 100644 --- a/packages/replay-canvas/CONTRIBUTING.md +++ b/packages/replay-canvas/CONTRIBUTING.md @@ -3,5 +3,5 @@ When [updating the `rrweb` dependency](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/package.json?plain=1#LL55), please be aware that -[`@sentry/replay`'s README.md](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/README.md?plain=1#LL204) +[`@sentry-internal/replay`'s README.md](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/README.md?plain=1#LL204) also needs to be updated. diff --git a/packages/replay-canvas/package.json b/packages/replay-canvas/package.json index 393b9d227250..77ea29fa4345 100644 --- a/packages/replay-canvas/package.json +++ b/packages/replay-canvas/package.json @@ -73,7 +73,7 @@ }, "dependencies": { "@sentry/core": "8.0.0-alpha.4", - "@sentry/replay": "8.0.0-alpha.4", + "@sentry-internal/replay": "8.0.0-alpha.4", "@sentry/types": "8.0.0-alpha.4", "@sentry/utils": "8.0.0-alpha.4" }, diff --git a/packages/replay-canvas/src/canvas.ts b/packages/replay-canvas/src/canvas.ts index 1a2ae0126be9..b9dcf8f4b75c 100644 --- a/packages/replay-canvas/src/canvas.ts +++ b/packages/replay-canvas/src/canvas.ts @@ -1,6 +1,6 @@ +import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry-internal/replay'; import { CanvasManager } from '@sentry-internal/rrweb'; import { defineIntegration } from '@sentry/core'; -import type { CanvasManagerInterface, CanvasManagerOptions } from '@sentry/replay'; import type { IntegrationFn } from '@sentry/types'; interface ReplayCanvasOptions { diff --git a/packages/replay/.eslintignore b/packages/replay-internal/.eslintignore similarity index 100% rename from packages/replay/.eslintignore rename to packages/replay-internal/.eslintignore diff --git a/packages/replay/.eslintrc.js b/packages/replay-internal/.eslintrc.js similarity index 100% rename from packages/replay/.eslintrc.js rename to packages/replay-internal/.eslintrc.js diff --git a/packages/replay/.gitignore b/packages/replay-internal/.gitignore similarity index 100% rename from packages/replay/.gitignore rename to packages/replay-internal/.gitignore diff --git a/packages/replay/CONTRIBUTING.md b/packages/replay-internal/CONTRIBUTING.md similarity index 59% rename from packages/replay/CONTRIBUTING.md rename to packages/replay-internal/CONTRIBUTING.md index 7b4a70f075ab..b82dc89e3d70 100644 --- a/packages/replay/CONTRIBUTING.md +++ b/packages/replay-internal/CONTRIBUTING.md @@ -3,5 +3,5 @@ When [updating the `rrweb` dependency](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/package.json?plain=1#LL55), please be aware that -[`@sentry/replay`'s README.md](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/README.md?plain=1#LL204) +[`@sentry-internal/replay`'s README.md](https://github.com/getsentry/sentry-javascript/blob/a493aa6a46555b944c8d896a2164bcd8b11caaf5/packages/replay/README.md?plain=1#LL204) also needs to be updated. diff --git a/packages/replay/LICENSE b/packages/replay-internal/LICENSE similarity index 100% rename from packages/replay/LICENSE rename to packages/replay-internal/LICENSE diff --git a/packages/replay/README.md b/packages/replay-internal/README.md similarity index 96% rename from packages/replay/README.md rename to packages/replay-internal/README.md index 2583065c9787..9533593acead 100644 --- a/packages/replay/README.md +++ b/packages/replay-internal/README.md @@ -6,13 +6,16 @@ # Sentry Session Replay -[![npm version](https://img.shields.io/npm/v/@sentry/replay.svg)](https://www.npmjs.com/package/@sentry/replay) -[![npm dm](https://img.shields.io/npm/dm/@sentry/replay.svg)](https://www.npmjs.com/package/@sentry/replay) -[![npm dt](https://img.shields.io/npm/dt/@sentry/replay.svg)](https://www.npmjs.com/package/@sentry/replay) +[![npm version](https://img.shields.io/npm/v/@sentry-internal/replay.svg)](https://www.npmjs.com/package/@sentry-internal/replay) +[![npm dm](https://img.shields.io/npm/dm/@sentry-internal/replay.svg)](https://www.npmjs.com/package/@sentry-internal/replay) +[![npm dt](https://img.shields.io/npm/dt/@sentry-internal/replay.svg)](https://www.npmjs.com/package/@sentry-internal/replay) + +This is an internal package that is being re-exported in `@sentry/browser` and other browser-related SDKs like +`@sentry/react` or `@sentry/vue`. ## Pre-requisites -`@sentry/replay` requires Node 14+, and browsers newer than IE11. +`@sentry-internal/replay` requires Node 14+, and browsers newer than IE11. ## Installation diff --git a/packages/replay/jest.config.ts b/packages/replay-internal/jest.config.ts similarity index 100% rename from packages/replay/jest.config.ts rename to packages/replay-internal/jest.config.ts diff --git a/packages/replay/jest.setup.ts b/packages/replay-internal/jest.setup.ts similarity index 100% rename from packages/replay/jest.setup.ts rename to packages/replay-internal/jest.setup.ts diff --git a/packages/replay/package.json b/packages/replay-internal/package.json similarity index 98% rename from packages/replay/package.json rename to packages/replay-internal/package.json index 340180d90183..20fc3a8cc8c3 100644 --- a/packages/replay/package.json +++ b/packages/replay-internal/package.json @@ -1,5 +1,5 @@ { - "name": "@sentry/replay", + "name": "@sentry-internal/replay", "version": "8.0.0-alpha.4", "description": "User replays for Sentry", "main": "build/npm/cjs/index.js", diff --git a/packages/replay/rollup.bundle.config.mjs b/packages/replay-internal/rollup.bundle.config.mjs similarity index 88% rename from packages/replay/rollup.bundle.config.mjs rename to packages/replay-internal/rollup.bundle.config.mjs index 8bdc41f8001c..9d1b9d412fed 100644 --- a/packages/replay/rollup.bundle.config.mjs +++ b/packages/replay-internal/rollup.bundle.config.mjs @@ -3,7 +3,7 @@ import { makeBaseBundleConfig, makeBundleConfigVariants } from '@sentry-internal const baseBundleConfig = makeBaseBundleConfig({ bundleType: 'addon', entrypoints: ['src/index.ts'], - licenseTitle: '@sentry/replay', + licenseTitle: '@sentry-internal/replay', outputFileBase: () => 'bundles/replay', }); diff --git a/packages/replay/rollup.npm.config.mjs b/packages/replay-internal/rollup.npm.config.mjs similarity index 100% rename from packages/replay/rollup.npm.config.mjs rename to packages/replay-internal/rollup.npm.config.mjs diff --git a/packages/replay/scripts/craft-pre-release.sh b/packages/replay-internal/scripts/craft-pre-release.sh similarity index 100% rename from packages/replay/scripts/craft-pre-release.sh rename to packages/replay-internal/scripts/craft-pre-release.sh diff --git a/packages/replay/src/constants.ts b/packages/replay-internal/src/constants.ts similarity index 100% rename from packages/replay/src/constants.ts rename to packages/replay-internal/src/constants.ts diff --git a/packages/replay/src/coreHandlers/handleAfterSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleAfterSendEvent.ts rename to packages/replay-internal/src/coreHandlers/handleAfterSendEvent.ts diff --git a/packages/replay/src/coreHandlers/handleBeforeSendEvent.ts b/packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleBeforeSendEvent.ts rename to packages/replay-internal/src/coreHandlers/handleBeforeSendEvent.ts diff --git a/packages/replay/src/coreHandlers/handleBreadcrumbs.ts b/packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleBreadcrumbs.ts rename to packages/replay-internal/src/coreHandlers/handleBreadcrumbs.ts diff --git a/packages/replay/src/coreHandlers/handleClick.ts b/packages/replay-internal/src/coreHandlers/handleClick.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleClick.ts rename to packages/replay-internal/src/coreHandlers/handleClick.ts diff --git a/packages/replay/src/coreHandlers/handleDom.ts b/packages/replay-internal/src/coreHandlers/handleDom.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleDom.ts rename to packages/replay-internal/src/coreHandlers/handleDom.ts diff --git a/packages/replay/src/coreHandlers/handleGlobalEvent.ts b/packages/replay-internal/src/coreHandlers/handleGlobalEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleGlobalEvent.ts rename to packages/replay-internal/src/coreHandlers/handleGlobalEvent.ts diff --git a/packages/replay/src/coreHandlers/handleHistory.ts b/packages/replay-internal/src/coreHandlers/handleHistory.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleHistory.ts rename to packages/replay-internal/src/coreHandlers/handleHistory.ts diff --git a/packages/replay/src/coreHandlers/handleKeyboardEvent.ts b/packages/replay-internal/src/coreHandlers/handleKeyboardEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleKeyboardEvent.ts rename to packages/replay-internal/src/coreHandlers/handleKeyboardEvent.ts diff --git a/packages/replay/src/coreHandlers/handleNetworkBreadcrumbs.ts b/packages/replay-internal/src/coreHandlers/handleNetworkBreadcrumbs.ts similarity index 100% rename from packages/replay/src/coreHandlers/handleNetworkBreadcrumbs.ts rename to packages/replay-internal/src/coreHandlers/handleNetworkBreadcrumbs.ts diff --git a/packages/replay/src/coreHandlers/performanceObserver.ts b/packages/replay-internal/src/coreHandlers/performanceObserver.ts similarity index 100% rename from packages/replay/src/coreHandlers/performanceObserver.ts rename to packages/replay-internal/src/coreHandlers/performanceObserver.ts diff --git a/packages/replay/src/coreHandlers/util/addBreadcrumbEvent.ts b/packages/replay-internal/src/coreHandlers/util/addBreadcrumbEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/addBreadcrumbEvent.ts rename to packages/replay-internal/src/coreHandlers/util/addBreadcrumbEvent.ts diff --git a/packages/replay/src/coreHandlers/util/addFeedbackBreadcrumb.ts b/packages/replay-internal/src/coreHandlers/util/addFeedbackBreadcrumb.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/addFeedbackBreadcrumb.ts rename to packages/replay-internal/src/coreHandlers/util/addFeedbackBreadcrumb.ts diff --git a/packages/replay/src/coreHandlers/util/addNetworkBreadcrumb.ts b/packages/replay-internal/src/coreHandlers/util/addNetworkBreadcrumb.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/addNetworkBreadcrumb.ts rename to packages/replay-internal/src/coreHandlers/util/addNetworkBreadcrumb.ts diff --git a/packages/replay/src/coreHandlers/util/domUtils.ts b/packages/replay-internal/src/coreHandlers/util/domUtils.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/domUtils.ts rename to packages/replay-internal/src/coreHandlers/util/domUtils.ts diff --git a/packages/replay/src/coreHandlers/util/fetchUtils.ts b/packages/replay-internal/src/coreHandlers/util/fetchUtils.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/fetchUtils.ts rename to packages/replay-internal/src/coreHandlers/util/fetchUtils.ts diff --git a/packages/replay/src/coreHandlers/util/getAttributesToRecord.ts b/packages/replay-internal/src/coreHandlers/util/getAttributesToRecord.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/getAttributesToRecord.ts rename to packages/replay-internal/src/coreHandlers/util/getAttributesToRecord.ts diff --git a/packages/replay/src/coreHandlers/util/networkUtils.ts b/packages/replay-internal/src/coreHandlers/util/networkUtils.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/networkUtils.ts rename to packages/replay-internal/src/coreHandlers/util/networkUtils.ts diff --git a/packages/replay/src/coreHandlers/util/onWindowOpen.ts b/packages/replay-internal/src/coreHandlers/util/onWindowOpen.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/onWindowOpen.ts rename to packages/replay-internal/src/coreHandlers/util/onWindowOpen.ts diff --git a/packages/replay/src/coreHandlers/util/shouldSampleForBufferEvent.ts b/packages/replay-internal/src/coreHandlers/util/shouldSampleForBufferEvent.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/shouldSampleForBufferEvent.ts rename to packages/replay-internal/src/coreHandlers/util/shouldSampleForBufferEvent.ts diff --git a/packages/replay/src/coreHandlers/util/xhrUtils.ts b/packages/replay-internal/src/coreHandlers/util/xhrUtils.ts similarity index 100% rename from packages/replay/src/coreHandlers/util/xhrUtils.ts rename to packages/replay-internal/src/coreHandlers/util/xhrUtils.ts diff --git a/packages/replay/src/debug-build.ts b/packages/replay-internal/src/debug-build.ts similarity index 100% rename from packages/replay/src/debug-build.ts rename to packages/replay-internal/src/debug-build.ts diff --git a/packages/replay/src/eventBuffer/EventBufferArray.ts b/packages/replay-internal/src/eventBuffer/EventBufferArray.ts similarity index 100% rename from packages/replay/src/eventBuffer/EventBufferArray.ts rename to packages/replay-internal/src/eventBuffer/EventBufferArray.ts diff --git a/packages/replay/src/eventBuffer/EventBufferCompressionWorker.ts b/packages/replay-internal/src/eventBuffer/EventBufferCompressionWorker.ts similarity index 100% rename from packages/replay/src/eventBuffer/EventBufferCompressionWorker.ts rename to packages/replay-internal/src/eventBuffer/EventBufferCompressionWorker.ts diff --git a/packages/replay/src/eventBuffer/EventBufferProxy.ts b/packages/replay-internal/src/eventBuffer/EventBufferProxy.ts similarity index 100% rename from packages/replay/src/eventBuffer/EventBufferProxy.ts rename to packages/replay-internal/src/eventBuffer/EventBufferProxy.ts diff --git a/packages/replay/src/eventBuffer/WorkerHandler.ts b/packages/replay-internal/src/eventBuffer/WorkerHandler.ts similarity index 100% rename from packages/replay/src/eventBuffer/WorkerHandler.ts rename to packages/replay-internal/src/eventBuffer/WorkerHandler.ts diff --git a/packages/replay/src/eventBuffer/error.ts b/packages/replay-internal/src/eventBuffer/error.ts similarity index 100% rename from packages/replay/src/eventBuffer/error.ts rename to packages/replay-internal/src/eventBuffer/error.ts diff --git a/packages/replay/src/eventBuffer/index.ts b/packages/replay-internal/src/eventBuffer/index.ts similarity index 100% rename from packages/replay/src/eventBuffer/index.ts rename to packages/replay-internal/src/eventBuffer/index.ts diff --git a/packages/replay/src/index.ts b/packages/replay-internal/src/index.ts similarity index 100% rename from packages/replay/src/index.ts rename to packages/replay-internal/src/index.ts diff --git a/packages/replay/src/integration.ts b/packages/replay-internal/src/integration.ts similarity index 100% rename from packages/replay/src/integration.ts rename to packages/replay-internal/src/integration.ts diff --git a/packages/replay/src/replay.ts b/packages/replay-internal/src/replay.ts similarity index 100% rename from packages/replay/src/replay.ts rename to packages/replay-internal/src/replay.ts diff --git a/packages/replay/src/session/Session.ts b/packages/replay-internal/src/session/Session.ts similarity index 100% rename from packages/replay/src/session/Session.ts rename to packages/replay-internal/src/session/Session.ts diff --git a/packages/replay/src/session/clearSession.ts b/packages/replay-internal/src/session/clearSession.ts similarity index 100% rename from packages/replay/src/session/clearSession.ts rename to packages/replay-internal/src/session/clearSession.ts diff --git a/packages/replay/src/session/createSession.ts b/packages/replay-internal/src/session/createSession.ts similarity index 100% rename from packages/replay/src/session/createSession.ts rename to packages/replay-internal/src/session/createSession.ts diff --git a/packages/replay/src/session/fetchSession.ts b/packages/replay-internal/src/session/fetchSession.ts similarity index 100% rename from packages/replay/src/session/fetchSession.ts rename to packages/replay-internal/src/session/fetchSession.ts diff --git a/packages/replay/src/session/index.ts b/packages/replay-internal/src/session/index.ts similarity index 100% rename from packages/replay/src/session/index.ts rename to packages/replay-internal/src/session/index.ts diff --git a/packages/replay/src/session/loadOrCreateSession.ts b/packages/replay-internal/src/session/loadOrCreateSession.ts similarity index 100% rename from packages/replay/src/session/loadOrCreateSession.ts rename to packages/replay-internal/src/session/loadOrCreateSession.ts diff --git a/packages/replay/src/session/saveSession.ts b/packages/replay-internal/src/session/saveSession.ts similarity index 100% rename from packages/replay/src/session/saveSession.ts rename to packages/replay-internal/src/session/saveSession.ts diff --git a/packages/replay/src/session/shouldRefreshSession.ts b/packages/replay-internal/src/session/shouldRefreshSession.ts similarity index 100% rename from packages/replay/src/session/shouldRefreshSession.ts rename to packages/replay-internal/src/session/shouldRefreshSession.ts diff --git a/packages/replay/src/types/index.ts b/packages/replay-internal/src/types/index.ts similarity index 100% rename from packages/replay/src/types/index.ts rename to packages/replay-internal/src/types/index.ts diff --git a/packages/replay/src/types/performance.ts b/packages/replay-internal/src/types/performance.ts similarity index 100% rename from packages/replay/src/types/performance.ts rename to packages/replay-internal/src/types/performance.ts diff --git a/packages/replay/src/types/replay.ts b/packages/replay-internal/src/types/replay.ts similarity index 100% rename from packages/replay/src/types/replay.ts rename to packages/replay-internal/src/types/replay.ts diff --git a/packages/replay/src/types/replayFrame.ts b/packages/replay-internal/src/types/replayFrame.ts similarity index 100% rename from packages/replay/src/types/replayFrame.ts rename to packages/replay-internal/src/types/replayFrame.ts diff --git a/packages/replay/src/types/request.ts b/packages/replay-internal/src/types/request.ts similarity index 100% rename from packages/replay/src/types/request.ts rename to packages/replay-internal/src/types/request.ts diff --git a/packages/replay/src/types/rrweb.ts b/packages/replay-internal/src/types/rrweb.ts similarity index 100% rename from packages/replay/src/types/rrweb.ts rename to packages/replay-internal/src/types/rrweb.ts diff --git a/packages/replay/src/util/addEvent.ts b/packages/replay-internal/src/util/addEvent.ts similarity index 100% rename from packages/replay/src/util/addEvent.ts rename to packages/replay-internal/src/util/addEvent.ts diff --git a/packages/replay/src/util/addGlobalListeners.ts b/packages/replay-internal/src/util/addGlobalListeners.ts similarity index 100% rename from packages/replay/src/util/addGlobalListeners.ts rename to packages/replay-internal/src/util/addGlobalListeners.ts diff --git a/packages/replay/src/util/addMemoryEntry.ts b/packages/replay-internal/src/util/addMemoryEntry.ts similarity index 100% rename from packages/replay/src/util/addMemoryEntry.ts rename to packages/replay-internal/src/util/addMemoryEntry.ts diff --git a/packages/replay/src/util/createBreadcrumb.ts b/packages/replay-internal/src/util/createBreadcrumb.ts similarity index 100% rename from packages/replay/src/util/createBreadcrumb.ts rename to packages/replay-internal/src/util/createBreadcrumb.ts diff --git a/packages/replay/src/util/createPerformanceEntries.ts b/packages/replay-internal/src/util/createPerformanceEntries.ts similarity index 100% rename from packages/replay/src/util/createPerformanceEntries.ts rename to packages/replay-internal/src/util/createPerformanceEntries.ts diff --git a/packages/replay/src/util/createPerformanceSpans.ts b/packages/replay-internal/src/util/createPerformanceSpans.ts similarity index 100% rename from packages/replay/src/util/createPerformanceSpans.ts rename to packages/replay-internal/src/util/createPerformanceSpans.ts diff --git a/packages/replay/src/util/createReplayEnvelope.ts b/packages/replay-internal/src/util/createReplayEnvelope.ts similarity index 100% rename from packages/replay/src/util/createReplayEnvelope.ts rename to packages/replay-internal/src/util/createReplayEnvelope.ts diff --git a/packages/replay/src/util/debounce.ts b/packages/replay-internal/src/util/debounce.ts similarity index 100% rename from packages/replay/src/util/debounce.ts rename to packages/replay-internal/src/util/debounce.ts diff --git a/packages/replay/src/util/eventUtils.ts b/packages/replay-internal/src/util/eventUtils.ts similarity index 100% rename from packages/replay/src/util/eventUtils.ts rename to packages/replay-internal/src/util/eventUtils.ts diff --git a/packages/replay/src/util/getPrivacyOptions.ts b/packages/replay-internal/src/util/getPrivacyOptions.ts similarity index 100% rename from packages/replay/src/util/getPrivacyOptions.ts rename to packages/replay-internal/src/util/getPrivacyOptions.ts diff --git a/packages/replay/src/util/getReplay.ts b/packages/replay-internal/src/util/getReplay.ts similarity index 100% rename from packages/replay/src/util/getReplay.ts rename to packages/replay-internal/src/util/getReplay.ts diff --git a/packages/replay/src/util/handleRecordingEmit.ts b/packages/replay-internal/src/util/handleRecordingEmit.ts similarity index 100% rename from packages/replay/src/util/handleRecordingEmit.ts rename to packages/replay-internal/src/util/handleRecordingEmit.ts diff --git a/packages/replay/src/util/hasSessionStorage.ts b/packages/replay-internal/src/util/hasSessionStorage.ts similarity index 100% rename from packages/replay/src/util/hasSessionStorage.ts rename to packages/replay-internal/src/util/hasSessionStorage.ts diff --git a/packages/replay/src/util/isExpired.ts b/packages/replay-internal/src/util/isExpired.ts similarity index 100% rename from packages/replay/src/util/isExpired.ts rename to packages/replay-internal/src/util/isExpired.ts diff --git a/packages/replay/src/util/isRrwebError.ts b/packages/replay-internal/src/util/isRrwebError.ts similarity index 100% rename from packages/replay/src/util/isRrwebError.ts rename to packages/replay-internal/src/util/isRrwebError.ts diff --git a/packages/replay/src/util/isSampled.ts b/packages/replay-internal/src/util/isSampled.ts similarity index 100% rename from packages/replay/src/util/isSampled.ts rename to packages/replay-internal/src/util/isSampled.ts diff --git a/packages/replay/src/util/isSessionExpired.ts b/packages/replay-internal/src/util/isSessionExpired.ts similarity index 100% rename from packages/replay/src/util/isSessionExpired.ts rename to packages/replay-internal/src/util/isSessionExpired.ts diff --git a/packages/replay/src/util/log.ts b/packages/replay-internal/src/util/log.ts similarity index 100% rename from packages/replay/src/util/log.ts rename to packages/replay-internal/src/util/log.ts diff --git a/packages/replay/src/util/maskAttribute.ts b/packages/replay-internal/src/util/maskAttribute.ts similarity index 100% rename from packages/replay/src/util/maskAttribute.ts rename to packages/replay-internal/src/util/maskAttribute.ts diff --git a/packages/replay/src/util/prepareRecordingData.ts b/packages/replay-internal/src/util/prepareRecordingData.ts similarity index 100% rename from packages/replay/src/util/prepareRecordingData.ts rename to packages/replay-internal/src/util/prepareRecordingData.ts diff --git a/packages/replay/src/util/prepareReplayEvent.ts b/packages/replay-internal/src/util/prepareReplayEvent.ts similarity index 100% rename from packages/replay/src/util/prepareReplayEvent.ts rename to packages/replay-internal/src/util/prepareReplayEvent.ts diff --git a/packages/replay/src/util/sendReplay.ts b/packages/replay-internal/src/util/sendReplay.ts similarity index 100% rename from packages/replay/src/util/sendReplay.ts rename to packages/replay-internal/src/util/sendReplay.ts diff --git a/packages/replay/src/util/sendReplayRequest.ts b/packages/replay-internal/src/util/sendReplayRequest.ts similarity index 100% rename from packages/replay/src/util/sendReplayRequest.ts rename to packages/replay-internal/src/util/sendReplayRequest.ts diff --git a/packages/replay/src/util/shouldFilterRequest.ts b/packages/replay-internal/src/util/shouldFilterRequest.ts similarity index 100% rename from packages/replay/src/util/shouldFilterRequest.ts rename to packages/replay-internal/src/util/shouldFilterRequest.ts diff --git a/packages/replay/src/util/throttle.ts b/packages/replay-internal/src/util/throttle.ts similarity index 100% rename from packages/replay/src/util/throttle.ts rename to packages/replay-internal/src/util/throttle.ts diff --git a/packages/replay/src/util/timestamp.ts b/packages/replay-internal/src/util/timestamp.ts similarity index 100% rename from packages/replay/src/util/timestamp.ts rename to packages/replay-internal/src/util/timestamp.ts diff --git a/packages/replay/test/fixtures/error.ts b/packages/replay-internal/test/fixtures/error.ts similarity index 100% rename from packages/replay/test/fixtures/error.ts rename to packages/replay-internal/test/fixtures/error.ts diff --git a/packages/replay/test/fixtures/fixJson/1_completeJson.json b/packages/replay-internal/test/fixtures/fixJson/1_completeJson.json similarity index 100% rename from packages/replay/test/fixtures/fixJson/1_completeJson.json rename to packages/replay-internal/test/fixtures/fixJson/1_completeJson.json diff --git a/packages/replay/test/fixtures/fixJson/1_incompleteJson.txt b/packages/replay-internal/test/fixtures/fixJson/1_incompleteJson.txt similarity index 100% rename from packages/replay/test/fixtures/fixJson/1_incompleteJson.txt rename to packages/replay-internal/test/fixtures/fixJson/1_incompleteJson.txt diff --git a/packages/replay/test/fixtures/fixJson/2_completeJson.json b/packages/replay-internal/test/fixtures/fixJson/2_completeJson.json similarity index 100% rename from packages/replay/test/fixtures/fixJson/2_completeJson.json rename to packages/replay-internal/test/fixtures/fixJson/2_completeJson.json diff --git a/packages/replay/test/fixtures/fixJson/2_incompleteJson.txt b/packages/replay-internal/test/fixtures/fixJson/2_incompleteJson.txt similarity index 100% rename from packages/replay/test/fixtures/fixJson/2_incompleteJson.txt rename to packages/replay-internal/test/fixtures/fixJson/2_incompleteJson.txt diff --git a/packages/replay/test/fixtures/performanceEntry/navigation.ts b/packages/replay-internal/test/fixtures/performanceEntry/navigation.ts similarity index 100% rename from packages/replay/test/fixtures/performanceEntry/navigation.ts rename to packages/replay-internal/test/fixtures/performanceEntry/navigation.ts diff --git a/packages/replay/test/fixtures/performanceEntry/resource.ts b/packages/replay-internal/test/fixtures/performanceEntry/resource.ts similarity index 100% rename from packages/replay/test/fixtures/performanceEntry/resource.ts rename to packages/replay-internal/test/fixtures/performanceEntry/resource.ts diff --git a/packages/replay/test/fixtures/transaction.ts b/packages/replay-internal/test/fixtures/transaction.ts similarity index 100% rename from packages/replay/test/fixtures/transaction.ts rename to packages/replay-internal/test/fixtures/transaction.ts diff --git a/packages/replay/test/index.ts b/packages/replay-internal/test/index.ts similarity index 100% rename from packages/replay/test/index.ts rename to packages/replay-internal/test/index.ts diff --git a/packages/replay/test/integration/autoSaveSession.test.ts b/packages/replay-internal/test/integration/autoSaveSession.test.ts similarity index 100% rename from packages/replay/test/integration/autoSaveSession.test.ts rename to packages/replay-internal/test/integration/autoSaveSession.test.ts diff --git a/packages/replay/test/integration/beforeAddRecordingEvent.test.ts b/packages/replay-internal/test/integration/beforeAddRecordingEvent.test.ts similarity index 100% rename from packages/replay/test/integration/beforeAddRecordingEvent.test.ts rename to packages/replay-internal/test/integration/beforeAddRecordingEvent.test.ts diff --git a/packages/replay/test/integration/coreHandlers/handleAfterSendEvent.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts similarity index 100% rename from packages/replay/test/integration/coreHandlers/handleAfterSendEvent.test.ts rename to packages/replay-internal/test/integration/coreHandlers/handleAfterSendEvent.test.ts diff --git a/packages/replay/test/integration/coreHandlers/handleBeforeSendEvent.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleBeforeSendEvent.test.ts similarity index 100% rename from packages/replay/test/integration/coreHandlers/handleBeforeSendEvent.test.ts rename to packages/replay-internal/test/integration/coreHandlers/handleBeforeSendEvent.test.ts diff --git a/packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts b/packages/replay-internal/test/integration/coreHandlers/handleGlobalEvent.test.ts similarity index 100% rename from packages/replay/test/integration/coreHandlers/handleGlobalEvent.test.ts rename to packages/replay-internal/test/integration/coreHandlers/handleGlobalEvent.test.ts diff --git a/packages/replay/test/integration/errorSampleRate.test.ts b/packages/replay-internal/test/integration/errorSampleRate.test.ts similarity index 100% rename from packages/replay/test/integration/errorSampleRate.test.ts rename to packages/replay-internal/test/integration/errorSampleRate.test.ts diff --git a/packages/replay/test/integration/eventProcessors.test.ts b/packages/replay-internal/test/integration/eventProcessors.test.ts similarity index 100% rename from packages/replay/test/integration/eventProcessors.test.ts rename to packages/replay-internal/test/integration/eventProcessors.test.ts diff --git a/packages/replay/test/integration/events.test.ts b/packages/replay-internal/test/integration/events.test.ts similarity index 100% rename from packages/replay/test/integration/events.test.ts rename to packages/replay-internal/test/integration/events.test.ts diff --git a/packages/replay/test/integration/flush.test.ts b/packages/replay-internal/test/integration/flush.test.ts similarity index 100% rename from packages/replay/test/integration/flush.test.ts rename to packages/replay-internal/test/integration/flush.test.ts diff --git a/packages/replay/test/integration/getReplayId.test.ts b/packages/replay-internal/test/integration/getReplayId.test.ts similarity index 100% rename from packages/replay/test/integration/getReplayId.test.ts rename to packages/replay-internal/test/integration/getReplayId.test.ts diff --git a/packages/replay/test/integration/integrationSettings.test.ts b/packages/replay-internal/test/integration/integrationSettings.test.ts similarity index 100% rename from packages/replay/test/integration/integrationSettings.test.ts rename to packages/replay-internal/test/integration/integrationSettings.test.ts diff --git a/packages/replay/test/integration/rateLimiting.test.ts b/packages/replay-internal/test/integration/rateLimiting.test.ts similarity index 100% rename from packages/replay/test/integration/rateLimiting.test.ts rename to packages/replay-internal/test/integration/rateLimiting.test.ts diff --git a/packages/replay/test/integration/rrweb.test.ts b/packages/replay-internal/test/integration/rrweb.test.ts similarity index 100% rename from packages/replay/test/integration/rrweb.test.ts rename to packages/replay-internal/test/integration/rrweb.test.ts diff --git a/packages/replay/test/integration/sampling.test.ts b/packages/replay-internal/test/integration/sampling.test.ts similarity index 100% rename from packages/replay/test/integration/sampling.test.ts rename to packages/replay-internal/test/integration/sampling.test.ts diff --git a/packages/replay/test/integration/sendReplayEvent.test.ts b/packages/replay-internal/test/integration/sendReplayEvent.test.ts similarity index 100% rename from packages/replay/test/integration/sendReplayEvent.test.ts rename to packages/replay-internal/test/integration/sendReplayEvent.test.ts diff --git a/packages/replay/test/integration/session.test.ts b/packages/replay-internal/test/integration/session.test.ts similarity index 100% rename from packages/replay/test/integration/session.test.ts rename to packages/replay-internal/test/integration/session.test.ts diff --git a/packages/replay/test/integration/shouldFilterRequest.test.ts b/packages/replay-internal/test/integration/shouldFilterRequest.test.ts similarity index 100% rename from packages/replay/test/integration/shouldFilterRequest.test.ts rename to packages/replay-internal/test/integration/shouldFilterRequest.test.ts diff --git a/packages/replay/test/integration/stop.test.ts b/packages/replay-internal/test/integration/stop.test.ts similarity index 100% rename from packages/replay/test/integration/stop.test.ts rename to packages/replay-internal/test/integration/stop.test.ts diff --git a/packages/replay/test/mocks/mockRrweb.ts b/packages/replay-internal/test/mocks/mockRrweb.ts similarity index 100% rename from packages/replay/test/mocks/mockRrweb.ts rename to packages/replay-internal/test/mocks/mockRrweb.ts diff --git a/packages/replay/test/mocks/mockSdk.ts b/packages/replay-internal/test/mocks/mockSdk.ts similarity index 100% rename from packages/replay/test/mocks/mockSdk.ts rename to packages/replay-internal/test/mocks/mockSdk.ts diff --git a/packages/replay/test/mocks/resetSdkMock.ts b/packages/replay-internal/test/mocks/resetSdkMock.ts similarity index 100% rename from packages/replay/test/mocks/resetSdkMock.ts rename to packages/replay-internal/test/mocks/resetSdkMock.ts diff --git a/packages/replay/test/types.ts b/packages/replay-internal/test/types.ts similarity index 100% rename from packages/replay/test/types.ts rename to packages/replay-internal/test/types.ts diff --git a/packages/replay/test/unit/coreHandlers/handleBreadcrumbs.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleBreadcrumbs.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/handleBreadcrumbs.test.ts rename to packages/replay-internal/test/unit/coreHandlers/handleBreadcrumbs.test.ts diff --git a/packages/replay/test/unit/coreHandlers/handleClick.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleClick.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/handleClick.test.ts rename to packages/replay-internal/test/unit/coreHandlers/handleClick.test.ts diff --git a/packages/replay/test/unit/coreHandlers/handleDom.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/handleDom.test.ts rename to packages/replay-internal/test/unit/coreHandlers/handleDom.test.ts diff --git a/packages/replay/test/unit/coreHandlers/handleKeyboardEvent.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleKeyboardEvent.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/handleKeyboardEvent.test.ts rename to packages/replay-internal/test/unit/coreHandlers/handleKeyboardEvent.test.ts diff --git a/packages/replay/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts b/packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts rename to packages/replay-internal/test/unit/coreHandlers/handleNetworkBreadcrumbs.test.ts diff --git a/packages/replay/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts b/packages/replay-internal/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts rename to packages/replay-internal/test/unit/coreHandlers/util/addBreadcrumbEvent.test.ts diff --git a/packages/replay/test/unit/coreHandlers/util/fetchUtils.test.ts b/packages/replay-internal/test/unit/coreHandlers/util/fetchUtils.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/util/fetchUtils.test.ts rename to packages/replay-internal/test/unit/coreHandlers/util/fetchUtils.test.ts diff --git a/packages/replay/test/unit/coreHandlers/util/getAttributesToRecord.test.ts b/packages/replay-internal/test/unit/coreHandlers/util/getAttributesToRecord.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/util/getAttributesToRecord.test.ts rename to packages/replay-internal/test/unit/coreHandlers/util/getAttributesToRecord.test.ts diff --git a/packages/replay/test/unit/coreHandlers/util/networkUtils.test.ts b/packages/replay-internal/test/unit/coreHandlers/util/networkUtils.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/util/networkUtils.test.ts rename to packages/replay-internal/test/unit/coreHandlers/util/networkUtils.test.ts diff --git a/packages/replay/test/unit/coreHandlers/util/xhrUtils.test.ts b/packages/replay-internal/test/unit/coreHandlers/util/xhrUtils.test.ts similarity index 100% rename from packages/replay/test/unit/coreHandlers/util/xhrUtils.test.ts rename to packages/replay-internal/test/unit/coreHandlers/util/xhrUtils.test.ts diff --git a/packages/replay/test/unit/eventBuffer/EventBufferArray.test.ts b/packages/replay-internal/test/unit/eventBuffer/EventBufferArray.test.ts similarity index 100% rename from packages/replay/test/unit/eventBuffer/EventBufferArray.test.ts rename to packages/replay-internal/test/unit/eventBuffer/EventBufferArray.test.ts diff --git a/packages/replay/test/unit/eventBuffer/EventBufferCompressionWorker.test.ts b/packages/replay-internal/test/unit/eventBuffer/EventBufferCompressionWorker.test.ts similarity index 100% rename from packages/replay/test/unit/eventBuffer/EventBufferCompressionWorker.test.ts rename to packages/replay-internal/test/unit/eventBuffer/EventBufferCompressionWorker.test.ts diff --git a/packages/replay/test/unit/eventBuffer/EventBufferProxy.test.ts b/packages/replay-internal/test/unit/eventBuffer/EventBufferProxy.test.ts similarity index 100% rename from packages/replay/test/unit/eventBuffer/EventBufferProxy.test.ts rename to packages/replay-internal/test/unit/eventBuffer/EventBufferProxy.test.ts diff --git a/packages/replay/test/unit/multipleInstances.test.ts b/packages/replay-internal/test/unit/multipleInstances.test.ts similarity index 100% rename from packages/replay/test/unit/multipleInstances.test.ts rename to packages/replay-internal/test/unit/multipleInstances.test.ts diff --git a/packages/replay/test/unit/session/createSession.test.ts b/packages/replay-internal/test/unit/session/createSession.test.ts similarity index 100% rename from packages/replay/test/unit/session/createSession.test.ts rename to packages/replay-internal/test/unit/session/createSession.test.ts diff --git a/packages/replay/test/unit/session/fetchSession.test.ts b/packages/replay-internal/test/unit/session/fetchSession.test.ts similarity index 100% rename from packages/replay/test/unit/session/fetchSession.test.ts rename to packages/replay-internal/test/unit/session/fetchSession.test.ts diff --git a/packages/replay/test/unit/session/loadOrCreateSession.test.ts b/packages/replay-internal/test/unit/session/loadOrCreateSession.test.ts similarity index 100% rename from packages/replay/test/unit/session/loadOrCreateSession.test.ts rename to packages/replay-internal/test/unit/session/loadOrCreateSession.test.ts diff --git a/packages/replay/test/unit/session/saveSession.test.ts b/packages/replay-internal/test/unit/session/saveSession.test.ts similarity index 100% rename from packages/replay/test/unit/session/saveSession.test.ts rename to packages/replay-internal/test/unit/session/saveSession.test.ts diff --git a/packages/replay/test/unit/session/sessionSampling.test.ts b/packages/replay-internal/test/unit/session/sessionSampling.test.ts similarity index 100% rename from packages/replay/test/unit/session/sessionSampling.test.ts rename to packages/replay-internal/test/unit/session/sessionSampling.test.ts diff --git a/packages/replay/test/unit/util/addEvent.test.ts b/packages/replay-internal/test/unit/util/addEvent.test.ts similarity index 100% rename from packages/replay/test/unit/util/addEvent.test.ts rename to packages/replay-internal/test/unit/util/addEvent.test.ts diff --git a/packages/replay/test/unit/util/createPerformanceEntry.test.ts b/packages/replay-internal/test/unit/util/createPerformanceEntry.test.ts similarity index 100% rename from packages/replay/test/unit/util/createPerformanceEntry.test.ts rename to packages/replay-internal/test/unit/util/createPerformanceEntry.test.ts diff --git a/packages/replay/test/unit/util/createReplayEnvelope.test.ts b/packages/replay-internal/test/unit/util/createReplayEnvelope.test.ts similarity index 100% rename from packages/replay/test/unit/util/createReplayEnvelope.test.ts rename to packages/replay-internal/test/unit/util/createReplayEnvelope.test.ts diff --git a/packages/replay/test/unit/util/debounce.test.ts b/packages/replay-internal/test/unit/util/debounce.test.ts similarity index 100% rename from packages/replay/test/unit/util/debounce.test.ts rename to packages/replay-internal/test/unit/util/debounce.test.ts diff --git a/packages/replay/test/unit/util/getPrivacyOptions.test.ts b/packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts similarity index 100% rename from packages/replay/test/unit/util/getPrivacyOptions.test.ts rename to packages/replay-internal/test/unit/util/getPrivacyOptions.test.ts diff --git a/packages/replay/test/unit/util/getReplay.test.ts b/packages/replay-internal/test/unit/util/getReplay.test.ts similarity index 100% rename from packages/replay/test/unit/util/getReplay.test.ts rename to packages/replay-internal/test/unit/util/getReplay.test.ts diff --git a/packages/replay/test/unit/util/handleRecordingEmit.test.ts b/packages/replay-internal/test/unit/util/handleRecordingEmit.test.ts similarity index 100% rename from packages/replay/test/unit/util/handleRecordingEmit.test.ts rename to packages/replay-internal/test/unit/util/handleRecordingEmit.test.ts diff --git a/packages/replay/test/unit/util/isExpired.test.ts b/packages/replay-internal/test/unit/util/isExpired.test.ts similarity index 100% rename from packages/replay/test/unit/util/isExpired.test.ts rename to packages/replay-internal/test/unit/util/isExpired.test.ts diff --git a/packages/replay/test/unit/util/isSampled.test.ts b/packages/replay-internal/test/unit/util/isSampled.test.ts similarity index 100% rename from packages/replay/test/unit/util/isSampled.test.ts rename to packages/replay-internal/test/unit/util/isSampled.test.ts diff --git a/packages/replay/test/unit/util/isSessionExpired.test.ts b/packages/replay-internal/test/unit/util/isSessionExpired.test.ts similarity index 100% rename from packages/replay/test/unit/util/isSessionExpired.test.ts rename to packages/replay-internal/test/unit/util/isSessionExpired.test.ts diff --git a/packages/replay/test/unit/util/maskAttribute.test.ts b/packages/replay-internal/test/unit/util/maskAttribute.test.ts similarity index 100% rename from packages/replay/test/unit/util/maskAttribute.test.ts rename to packages/replay-internal/test/unit/util/maskAttribute.test.ts diff --git a/packages/replay/test/unit/util/prepareReplayEvent.test.ts b/packages/replay-internal/test/unit/util/prepareReplayEvent.test.ts similarity index 100% rename from packages/replay/test/unit/util/prepareReplayEvent.test.ts rename to packages/replay-internal/test/unit/util/prepareReplayEvent.test.ts diff --git a/packages/replay/test/unit/util/throttle.test.ts b/packages/replay-internal/test/unit/util/throttle.test.ts similarity index 100% rename from packages/replay/test/unit/util/throttle.test.ts rename to packages/replay-internal/test/unit/util/throttle.test.ts diff --git a/packages/replay/test/utils/TestClient.ts b/packages/replay-internal/test/utils/TestClient.ts similarity index 100% rename from packages/replay/test/utils/TestClient.ts rename to packages/replay-internal/test/utils/TestClient.ts diff --git a/packages/replay/test/utils/compression.ts b/packages/replay-internal/test/utils/compression.ts similarity index 100% rename from packages/replay/test/utils/compression.ts rename to packages/replay-internal/test/utils/compression.ts diff --git a/packages/replay/test/utils/getTestEvent.ts b/packages/replay-internal/test/utils/getTestEvent.ts similarity index 100% rename from packages/replay/test/utils/getTestEvent.ts rename to packages/replay-internal/test/utils/getTestEvent.ts diff --git a/packages/replay/test/utils/setupReplayContainer.ts b/packages/replay-internal/test/utils/setupReplayContainer.ts similarity index 100% rename from packages/replay/test/utils/setupReplayContainer.ts rename to packages/replay-internal/test/utils/setupReplayContainer.ts diff --git a/packages/replay/test/utils/use-fake-timers.ts b/packages/replay-internal/test/utils/use-fake-timers.ts similarity index 100% rename from packages/replay/test/utils/use-fake-timers.ts rename to packages/replay-internal/test/utils/use-fake-timers.ts diff --git a/packages/replay/tsconfig.json b/packages/replay-internal/tsconfig.json similarity index 100% rename from packages/replay/tsconfig.json rename to packages/replay-internal/tsconfig.json diff --git a/packages/replay/tsconfig.test.json b/packages/replay-internal/tsconfig.test.json similarity index 100% rename from packages/replay/tsconfig.test.json rename to packages/replay-internal/tsconfig.test.json diff --git a/packages/replay/tsconfig.types.json b/packages/replay-internal/tsconfig.types.json similarity index 100% rename from packages/replay/tsconfig.types.json rename to packages/replay-internal/tsconfig.types.json diff --git a/packages/replay-worker/README.md b/packages/replay-worker/README.md index 970a0b3defb1..29d39df52d67 100644 --- a/packages/replay-worker/README.md +++ b/packages/replay-worker/README.md @@ -6,8 +6,8 @@ # Sentry Session Replay Worker -This is an internal package that is used by @sentry/replay. It generates a web worker and converts it to a string, so -that we can process it easier in replay. +This is an internal package that is used by @sentry-internal/replay. It generates a web worker and converts it to a +string, so that we can process it easier in replay. By extracting this into a dedicated (private, internal) package, we can streamline the build of replay. diff --git a/packages/replay-worker/package.json b/packages/replay-worker/package.json index e314845dcd90..b5cefdb110a9 100644 --- a/packages/replay-worker/package.json +++ b/packages/replay-worker/package.json @@ -1,7 +1,7 @@ { "name": "@sentry-internal/replay-worker", "version": "8.0.0-alpha.4", - "description": "Worker for @sentry/replay", + "description": "Worker for @sentry-internal/replay", "main": "build/npm/esm/index.js", "module": "build/npm/esm/index.js", "types": "build/npm/types/index.d.ts", diff --git a/packages/replay/MIGRATION.md b/packages/replay/MIGRATION.md deleted file mode 100644 index d61689499d7d..000000000000 --- a/packages/replay/MIGRATION.md +++ /dev/null @@ -1,156 +0,0 @@ -# End of Replay Beta - -> For further migration changes please refer to the [general SDK migration notes](../../MIGRATION.md). - -Because of experimentation and rapid iteration, during the Beta period some bugs and problems came up which have since -been fixed/improved. We **strongly** recommend anyone using Replay in a version before 7.39.0 to update to 7.39.0 or -newer, in order to prevent running Replay with known problems that have since been fixed. - -Below you can find a list of relevant replay issues that have been resolved until 7.39.0: - -## New features / improvements - -- Remove `autoplay` attribute from audio/video tags ([#59](https://github.com/getsentry/rrweb/pull/59)) -- Exclude fetching scripts that use `` ([#52](https://github.com/getsentry/rrweb/pull/52)) -- With maskAllText, mask the attributes: placeholder, title, `aria-label` -- Lower the flush max delay from 15 seconds to 5 seconds (#6761) -- Stop recording when retry fails (#6765) -- Stop without retry when receiving bad API response (#6773) -- Send client_report when replay sending fails (#7093) -- Stop recording when hitting a rate limit (#7018) -- Allow Replay to be used in Electron renderers with nodeIntegration enabled (#6644) -- Do not renew session in error mode (#6948) -- Remove default sample rates for replay (#6878) -- Add `flush` method to integration (#6776) -- Improve compression worker & fallback behavior (#6988, #6936, #6827) -- Improve error handling (#7087, #7094, #7010, getsentry/rrweb#16, #6856) -- Add more default block filters (#7233) - -## Fixes - -- Fix masking inputs on change when `maskAllInputs:false` ([#61](https://github.com/getsentry/rrweb/pull/61)) -- More robust `rootShadowHost` check ([#50](https://github.com/getsentry/rrweb/pull/50)) -- Fix duplicated textarea value ([#62](https://github.com/getsentry/rrweb/pull/62)) -- Handle removed attributes ([#65](https://github.com/getsentry/rrweb/pull/65)) -- Change LCP calculation (#7187, #7225) -- Fix debounced flushes not respecting `maxWait` (#7207, #7208) -- Fix svgs not getting unblocked (#7132) -- Fix missing fetch/xhr requests (#7134) -- Fix feature detection of PerformanceObserver (#7029) -- Fix `checkoutEveryNms` (#6722) -- Fix incorrect uncompressed recording size due to encoding (#6740) -- Ensure dropping replays works (#6522) -- Envelope send should be awaited in try/catch (#6625) -- Improve handling of `maskAllText` selector (#6637) - -# Upgrading Replay from 7.34.0 to 7.35.0 - #6645 - -This release will remove the ability to change the default rrweb recording options (outside of privacy options). The -following are the new configuration values all replays will use: `slimDOMOptions: 'all'` - Removes `script`, comments, -`favicon`, whitespace in `head`, and a few `meta` tags in `head` `recordCanvas: false` - This option did not do anything -as playback of recorded canvas means we would have to remove the playback sandbox (which is a security concern). -`inlineStylesheet: true` - Inlines styles into the recording itself instead of attempting to fetch it remotely. This -means that styles in the replay will reflect the styles at the time of recording and not the current styles of the -remote stylesheet. `collectFonts: true` - Attempts to load custom fonts. `inlineImages: false` - Does not inline images -to recording and instead loads the asset remotely. During playback, images may not load due to CORS (add sentry.io as an -origin). - -Additionally, we have streamlined the privacy options. The following table lists the deprecated value, and what it is -replaced by: - -| deprecated key | replaced by | description | -| ---------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | -| maskInputOptions | mask | Use CSS selectors in `mask` in order to mask all inputs of a certain type. For example, `input[type="address"]` | -| blockSelector | block | The selector(s) can be moved directly in the `block` array. | -| blockClass | block | Convert the class name to a CSS selector and add to `block` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | -| maskClass | mask | Convert the class name to a CSS selector and add to `mask` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | -| maskSelector | mask | The selector(s) can be moved directly in the `mask` array. | -| ignoreClass | ignore | Convert the class name to a CSS selector and add to `ignore` array. For example, `first-name` becomes `.first-name`. Regexes can be moved as-is. | - -# Upgrading Replay from 7.31.0 to 7.32.0 - -In 7.32.0, we have removed the default values for the replay sample rates. Previously, they were: - -- `replaysSessionSampleRate: 0.1` -- `replaysOnErrorSampleRate: 1.0` - -Now, you have to explicitly set the sample rates, otherwise they default to 0. - -# Upgrading Replay from 0.6.x to 7.24.0 - -The Sentry Replay integration was moved to the Sentry JavaScript SDK monorepo. Hence we're jumping from version 0.x to -the monorepo's 7.x version which is shared across all JS SDK packages. - -## Replay sample rates are defined on top level (https://github.com/getsentry/sentry-javascript/issues/6351) - -Instead of defining the sample rates on the integration like this: - -```js -Sentry.init({ - dsn: '__DSN__', - integrations: [ - new Replay({ - sessionSampleRate: 0.1, - errorSampleRate: 1.0, - }), - ], - // ... -}); -``` - -They are now defined on the top level of the SDK: - -```js -Sentry.init({ - dsn: '__DSN__', - replaysSessionSampleRate: 0.1, - replaysOnErrorSampleRate: 1.0, - integrations: [ - new Replay({ - // other replay config still goes in here - }), - ], -}); -``` - -Note that the sample rate options inside of `new Replay({})` have been deprecated and will be removed in a future -update. - -## Removed deprecated options (https://github.com/getsentry/sentry-javascript/pull/6370) - -Two options, which have been deprecated for some time, have been removed: - -- `replaysSamplingRate` - instead use `sessionSampleRate` -- `captureOnlyOnError` - instead use `errorSampleRate` - -## New NPM package structure (https://github.com/getsentry/sentry-javascript/issues/6280) - -The internal structure of the npm package has changed. This is unlikely to affect you, unless you have imported -something from e.g.: - -```js -import something from '@sentry/replay/submodule'; -``` - -If you only imported from `@sentry/replay`, this will not affect you. - -## Changed type name from `IEventBuffer` to `EventBuffer` (https://github.com/getsentry/sentry-javascript/pull/6416) - -It is highly unlikely to affect anybody, but the type `IEventBuffer` was renamed to `EventBuffer` for consistency. -Unless you manually imported this and used it somewhere in your codebase, this will not affect you. - -## Session object is now a plain object (https://github.com/getsentry/sentry-javascript/pull/6417) - -The `Session` object exported from Replay is now a plain object, instead of a class. This should not affect you unless -you specifically accessed this class & did custom things with it. - -## Reduce public API of Replay integration (https://github.com/getsentry/sentry-javascript/pull/6407) - -The result of `new Replay()` now has a much more limited public API. Only the following methods are exposed: - -```js -const replay = new Replay(); - -replay.start(); -replay.stop(); -``` diff --git a/scripts/node-unit-tests.ts b/scripts/node-unit-tests.ts index 972c6d76db65..94802525b4dd 100644 --- a/scripts/node-unit-tests.ts +++ b/scripts/node-unit-tests.ts @@ -17,7 +17,7 @@ const DEFAULT_SKIP_TESTS_PACKAGES = [ '@sentry/angular', '@sentry/svelte', '@sentry/profiling-node', - '@sentry/replay', + '@sentry-internal/replay', '@sentry-internal/replay-canvas', '@sentry-internal/replay-worker', '@sentry-internal/feedback', From b846671da3c2db6cde3028b1ff9d99bac69490e2 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 22 Mar 2024 09:36:03 -0400 Subject: [PATCH 05/39] feat(tracing): Remove `instrumentRoutingWithDefaults` (#11240) This functionality is no longer being used, so we can remove it and it's tests. Part of https://github.com/getsentry/sentry-javascript/issues/9885 since it makes it easier to port over browsertracing into browser package. --- .../tracing-internal/src/browser/router.ts | 72 ---------- .../test/browser/router.test.ts | 127 ------------------ 2 files changed, 199 deletions(-) delete mode 100644 packages/tracing-internal/src/browser/router.ts delete mode 100644 packages/tracing-internal/test/browser/router.test.ts diff --git a/packages/tracing-internal/src/browser/router.ts b/packages/tracing-internal/src/browser/router.ts deleted file mode 100644 index b94911046171..000000000000 --- a/packages/tracing-internal/src/browser/router.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, spanToJSON } from '@sentry/core'; -import type { Transaction, TransactionContext } from '@sentry/types'; -import { addHistoryInstrumentationHandler, browserPerformanceTimeOrigin, logger } from '@sentry/utils'; - -import { DEBUG_BUILD } from '../common/debug-build'; -import { WINDOW } from './types'; - -/** - * Default function implementing pageload and navigation transactions - */ -export function instrumentRoutingWithDefaults( - customStartTransaction: (context: TransactionContext) => T | undefined, - startTransactionOnPageLoad: boolean = true, - startTransactionOnLocationChange: boolean = true, -): void { - if (!WINDOW || !WINDOW.location) { - DEBUG_BUILD && logger.warn('Could not initialize routing instrumentation due to invalid location'); - return; - } - - let startingUrl: string | undefined = WINDOW.location.href; - - let activeTransaction: T | undefined; - if (startTransactionOnPageLoad) { - activeTransaction = customStartTransaction({ - name: WINDOW.location.pathname, - // pageload should always start at timeOrigin (and needs to be in s, not ms) - startTimestamp: browserPerformanceTimeOrigin ? browserPerformanceTimeOrigin / 1000 : undefined, - op: 'pageload', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser', - }, - }); - } - - if (startTransactionOnLocationChange) { - addHistoryInstrumentationHandler(({ to, from }) => { - /** - * This early return is there to account for some cases where a navigation transaction starts right after - * long-running pageload. We make sure that if `from` is undefined and a valid `startingURL` exists, we don't - * create an uneccessary navigation transaction. - * - * This was hard to duplicate, but this behavior stopped as soon as this fix was applied. This issue might also - * only be caused in certain development environments where the usage of a hot module reloader is causing - * errors. - */ - if (from === undefined && startingUrl && startingUrl.indexOf(to) !== -1) { - startingUrl = undefined; - return; - } - - if (from !== to) { - startingUrl = undefined; - if (activeTransaction) { - DEBUG_BUILD && - logger.log(`[Tracing] Finishing current transaction with op: ${spanToJSON(activeTransaction).op}`); - // If there's an open transaction on the scope, we need to finish it before creating an new one. - activeTransaction.end(); - } - activeTransaction = customStartTransaction({ - name: WINDOW.location.pathname, - op: 'navigation', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.browser', - }, - }); - } - }); - } -} diff --git a/packages/tracing-internal/test/browser/router.test.ts b/packages/tracing-internal/test/browser/router.test.ts deleted file mode 100644 index 12c44f9029c4..000000000000 --- a/packages/tracing-internal/test/browser/router.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, SEMANTIC_ATTRIBUTE_SENTRY_SOURCE } from '@sentry/core'; -import type { HandlerDataHistory } from '@sentry/types'; -import { JSDOM } from 'jsdom'; -import { conditionalTest } from '../../../node/test/utils'; - -import { instrumentRoutingWithDefaults } from '../../src/browser/router'; - -let mockChangeHistory: undefined | ((data: HandlerDataHistory) => void); -jest.mock('@sentry/utils', () => { - const actual = jest.requireActual('@sentry/utils'); - return { - ...actual, - addHistoryInstrumentationHandler: (callback: (data: HandlerDataHistory) => void): void => { - mockChangeHistory = callback; - }, - }; -}); - -conditionalTest({ min: 16 })('instrumentRoutingWithDefaults', () => { - const mockFinish = jest.fn(); - const customStartTransaction = jest.fn().mockReturnValue({ end: mockFinish }); - beforeEach(() => { - const dom = new JSDOM(); - // @ts-expect-error need to override global document - global.document = dom.window.document; - // @ts-expect-error need to override global document - global.window = dom.window; - // @ts-expect-error need to override global document - global.location = dom.window.location; - - customStartTransaction.mockClear(); - mockFinish.mockClear(); - }); - - it('does not start transactions if global location is undefined', () => { - // @ts-expect-error need to override global document - global.location = undefined; - instrumentRoutingWithDefaults(customStartTransaction); - expect(customStartTransaction).toHaveBeenCalledTimes(0); - }); - - it('starts a pageload transaction', () => { - instrumentRoutingWithDefaults(customStartTransaction); - expect(customStartTransaction).toHaveBeenCalledTimes(1); - expect(customStartTransaction).toHaveBeenLastCalledWith({ - name: 'blank', - op: 'pageload', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.pageload.browser', - }, - startTimestamp: expect.any(Number), - }); - }); - - it('does not start a pageload transaction if startTransactionOnPageLoad is false', () => { - instrumentRoutingWithDefaults(customStartTransaction, false); - expect(customStartTransaction).toHaveBeenCalledTimes(0); - }); - - describe('navigation transaction', () => { - beforeEach(() => { - mockChangeHistory = undefined; - }); - - it('it is not created automatically', () => { - instrumentRoutingWithDefaults(customStartTransaction); - expect(customStartTransaction).not.toHaveBeenCalledWith(expect.objectContaining({ op: 'navigation' })); - }); - - it('is created on location change', () => { - instrumentRoutingWithDefaults(customStartTransaction); - expect(mockChangeHistory).toBeDefined(); - mockChangeHistory!({ to: 'here', from: 'there' }); - - expect(customStartTransaction).toHaveBeenCalledTimes(2); - expect(customStartTransaction).toHaveBeenLastCalledWith({ - name: 'blank', - op: 'navigation', - attributes: { - [SEMANTIC_ATTRIBUTE_SENTRY_SOURCE]: 'url', - [SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN]: 'auto.navigation.browser', - }, - }); - }); - - it('is not created if startTransactionOnLocationChange is false', () => { - instrumentRoutingWithDefaults(customStartTransaction, true, false); - expect(mockChangeHistory).toBeUndefined(); - - expect(customStartTransaction).toHaveBeenCalledTimes(1); - }); - - it('finishes the last active transaction', () => { - instrumentRoutingWithDefaults(customStartTransaction); - - expect(mockChangeHistory).toBeDefined(); - - expect(mockFinish).toHaveBeenCalledTimes(0); - mockChangeHistory!({ to: 'here', from: 'there' }); - expect(mockFinish).toHaveBeenCalledTimes(1); - }); - - it('will finish active transaction multiple times', () => { - instrumentRoutingWithDefaults(customStartTransaction); - - expect(mockChangeHistory).toBeDefined(); - - expect(mockFinish).toHaveBeenCalledTimes(0); - mockChangeHistory!({ to: 'here', from: 'there' }); - expect(mockFinish).toHaveBeenCalledTimes(1); - mockChangeHistory!({ to: 'over/there', from: 'here' }); - expect(mockFinish).toHaveBeenCalledTimes(2); - mockChangeHistory!({ to: 'nowhere', from: 'over/there' }); - expect(mockFinish).toHaveBeenCalledTimes(3); - }); - - it('not created if `from` is equal to `to`', () => { - instrumentRoutingWithDefaults(customStartTransaction); - expect(mockChangeHistory).toBeDefined(); - mockChangeHistory!({ to: 'first/path', from: 'first/path' }); - - expect(customStartTransaction).toHaveBeenCalledTimes(1); - expect(customStartTransaction).not.toHaveBeenLastCalledWith('navigation'); - }); - }); -}); From b7bd95fd11cae4639fbd9a691fc19df79c47b42d Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 22 Mar 2024 10:36:00 -0400 Subject: [PATCH 06/39] ref(v8): change integration.setupOnce signature (#11238) Make `integration.setupOnce` accept no arguments. This will allow us to easily remove `addGlobalEventProcessor` which is deprecated API. This also means we can remove `IntegrationFnResult`, as the type signature of the functional and class based integrations are now the same. Next up - remove `addGlobalEventProcessor`! --- packages/core/src/integration.ts | 18 ++----- packages/core/test/lib/sdk.test.ts | 8 +-- packages/core/test/mocks/integration.ts | 6 +-- packages/feedback/src/core/integration.ts | 4 +- packages/feedback/src/modal/integration.ts | 4 +- .../feedback/src/screenshot/integration.ts | 4 +- .../src/integrations/anr/index.ts | 6 +-- packages/node/src/integrations/http.ts | 13 ++--- .../node/src/integrations/undici/index.ts | 13 ++--- .../test/integrations/contextlines.test.ts | 8 ++- packages/node/test/integrations/http.test.ts | 51 +++++++------------ .../src/node/integrations/express.ts | 2 +- .../src/node/integrations/mongo.ts | 4 +- packages/types/src/index.ts | 2 +- packages/types/src/integration.ts | 51 ++----------------- 15 files changed, 53 insertions(+), 141 deletions(-) diff --git a/packages/core/src/integration.ts b/packages/core/src/integration.ts index ccf1f86cff18..237a086b92bb 100644 --- a/packages/core/src/integration.ts +++ b/packages/core/src/integration.ts @@ -1,19 +1,8 @@ -import type { - Client, - Event, - EventHint, - Integration, - IntegrationClass, - IntegrationFn, - IntegrationFnResult, - Options, -} from '@sentry/types'; +import type { Client, Event, EventHint, Integration, IntegrationClass, IntegrationFn, Options } from '@sentry/types'; import { arrayify, logger } from '@sentry/utils'; import { getClient } from './currentScopes'; import { DEBUG_BUILD } from './debug-build'; -import { addGlobalEventProcessor } from './eventProcessors'; -import { getCurrentHub } from './hub'; declare module '@sentry/types' { interface Integration { @@ -130,8 +119,7 @@ export function setupIntegration(client: Client, integration: Integration, integ // `setupOnce` is only called the first time if (installedIntegrations.indexOf(integration.name) === -1 && typeof integration.setupOnce === 'function') { - // eslint-disable-next-line deprecation/deprecation - integration.setupOnce(addGlobalEventProcessor, getCurrentHub); + integration.setupOnce(); installedIntegrations.push(integration.name); } @@ -203,6 +191,6 @@ export function convertIntegrationFnToClass( * Define an integration function that can be used to create an integration instance. * Note that this by design hides the implementation details of the integration, as they are considered internal. */ -export function defineIntegration(fn: Fn): (...args: Parameters) => IntegrationFnResult { +export function defineIntegration(fn: Fn): (...args: Parameters) => Integration { return fn; } diff --git a/packages/core/test/lib/sdk.test.ts b/packages/core/test/lib/sdk.test.ts index 0117585d05ab..ecc7d18483e5 100644 --- a/packages/core/test/lib/sdk.test.ts +++ b/packages/core/test/lib/sdk.test.ts @@ -1,4 +1,4 @@ -import type { Client, Integration, IntegrationFnResult } from '@sentry/types'; +import type { Client, Integration } from '@sentry/types'; import { captureCheckIn, getCurrentScope, setCurrentClient } from '../../src'; import { installedIntegrations } from '../../src/integration'; @@ -43,20 +43,20 @@ describe('SDK', () => { name: 'integration1', setupOnce: jest.fn(() => list.push('setupOnce1')), afterAllSetup: jest.fn(() => list.push('afterAllSetup1')), - } satisfies IntegrationFnResult; + } satisfies Integration; const integration2 = { name: 'integration2', setupOnce: jest.fn(() => list.push('setupOnce2')), setup: jest.fn(() => list.push('setup2')), afterAllSetup: jest.fn(() => list.push('afterAllSetup2')), - } satisfies IntegrationFnResult; + } satisfies Integration; const integration3 = { name: 'integration3', setupOnce: jest.fn(() => list.push('setupOnce3')), setup: jest.fn(() => list.push('setup3')), - } satisfies IntegrationFnResult; + } satisfies Integration; const integrations: Integration[] = [integration1, integration2, integration3]; const options = getDefaultTestClientOptions({ dsn: PUBLIC_DSN, integrations }); diff --git a/packages/core/test/mocks/integration.ts b/packages/core/test/mocks/integration.ts index dbee06380d1c..ce012923030e 100644 --- a/packages/core/test/mocks/integration.ts +++ b/packages/core/test/mocks/integration.ts @@ -1,4 +1,4 @@ -import type { Event, EventProcessor, Integration } from '@sentry/types'; +import type { Client, Event, EventProcessor, Integration } from '@sentry/types'; import { getClient, getCurrentScope } from '../../src'; @@ -27,8 +27,8 @@ export class AddAttachmentTestIntegration implements Integration { public name: string = 'AddAttachmentTestIntegration'; - public setupOnce(addGlobalEventProcessor: (callback: EventProcessor) => void): void { - addGlobalEventProcessor((event, hint) => { + public setup(client: Client): void { + client.addEventProcessor((event, hint) => { hint.attachments = [...(hint.attachments || []), { filename: 'integration.file', data: 'great content!' }]; return event; }); diff --git a/packages/feedback/src/core/integration.ts b/packages/feedback/src/core/integration.ts index 489bfd32728d..befc2cc03495 100644 --- a/packages/feedback/src/core/integration.ts +++ b/packages/feedback/src/core/integration.ts @@ -1,5 +1,5 @@ import { defineIntegration, getClient } from '@sentry/core'; -import type { IntegrationFn, IntegrationFnResult } from '@sentry/types'; +import type { Integration, IntegrationFn } from '@sentry/types'; import { isBrowser, logger } from '@sentry/utils'; import { ACTOR_LABEL, @@ -42,7 +42,7 @@ interface PublicFeedbackIntegration { closeDialog: () => void; removeWidget: () => void; } -export type IFeedbackIntegration = IntegrationFnResult & PublicFeedbackIntegration; +export type IFeedbackIntegration = Integration & PublicFeedbackIntegration; export const _feedbackIntegration = (({ // FeedbackGeneralConfiguration diff --git a/packages/feedback/src/modal/integration.ts b/packages/feedback/src/modal/integration.ts index 67f2c327db5b..fa034650f023 100644 --- a/packages/feedback/src/modal/integration.ts +++ b/packages/feedback/src/modal/integration.ts @@ -1,5 +1,5 @@ import { defineIntegration } from '@sentry/core'; -import type { IntegrationFn, IntegrationFnResult } from '@sentry/types'; +import type { Integration, IntegrationFn } from '@sentry/types'; import { createDialog } from './createDialog'; interface PublicFeedbackModalIntegration { @@ -8,7 +8,7 @@ interface PublicFeedbackModalIntegration { const INTEGRATION_NAME = 'FeedbackModal'; -export type IFeedbackModalIntegration = IntegrationFnResult & PublicFeedbackModalIntegration; +export type IFeedbackModalIntegration = Integration & PublicFeedbackModalIntegration; export const _feedbackModalIntegration = (() => { return { diff --git a/packages/feedback/src/screenshot/integration.ts b/packages/feedback/src/screenshot/integration.ts index 93fb5b605e04..3b959b971d70 100644 --- a/packages/feedback/src/screenshot/integration.ts +++ b/packages/feedback/src/screenshot/integration.ts @@ -1,5 +1,5 @@ import { defineIntegration } from '@sentry/core'; -import type { IntegrationFn, IntegrationFnResult } from '@sentry/types'; +import type { Integration, IntegrationFn } from '@sentry/types'; import { createInput } from './createInput'; interface PublicFeedbackScreenshotIntegration { @@ -8,7 +8,7 @@ interface PublicFeedbackScreenshotIntegration { const INTEGRATION_NAME = 'FeedbackScreenshot'; -export type IFeedbackScreenshotIntegration = IntegrationFnResult & PublicFeedbackScreenshotIntegration; +export type IFeedbackScreenshotIntegration = Integration & PublicFeedbackScreenshotIntegration; export const _feedbackScreenshotIntegration = (() => { return { diff --git a/packages/node-experimental/src/integrations/anr/index.ts b/packages/node-experimental/src/integrations/anr/index.ts index 8e28e0eb3535..c1bc03bc5a86 100644 --- a/packages/node-experimental/src/integrations/anr/index.ts +++ b/packages/node-experimental/src/integrations/anr/index.ts @@ -1,5 +1,5 @@ import { defineIntegration, getCurrentScope } from '@sentry/core'; -import type { Contexts, Event, EventHint, IntegrationFn, IntegrationFnResult } from '@sentry/types'; +import type { Contexts, Event, EventHint, Integration, IntegrationFn } from '@sentry/types'; import { logger } from '@sentry/utils'; import * as inspector from 'inspector'; import { Worker } from 'worker_threads'; @@ -69,10 +69,10 @@ const _anrIntegration = ((options: Partial = {}) => { // This allows us to call into all integrations to fetch the full context setImmediate(() => this.startWorker()); }, - } as IntegrationFnResult & AnrInternal; + } as Integration & AnrInternal; }) satisfies IntegrationFn; -type AnrReturn = (options?: Partial) => IntegrationFnResult & AnrInternal; +type AnrReturn = (options?: Partial) => Integration & AnrInternal; export const anrIntegration = defineIntegration(_anrIntegration) as AnrReturn; diff --git a/packages/node/src/integrations/http.ts b/packages/node/src/integrations/http.ts index a8ca8b832455..bc4571f35af0 100644 --- a/packages/node/src/integrations/http.ts +++ b/packages/node/src/integrations/http.ts @@ -1,7 +1,6 @@ /* eslint-disable max-lines */ import type * as http from 'http'; import type * as https from 'https'; -import type { Hub } from '@sentry/core'; import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core'; import { defineIntegration, getIsolationScope, hasTracingEnabled } from '@sentry/core'; import { @@ -18,10 +17,8 @@ import { } from '@sentry/core'; import type { ClientOptions, - EventProcessor, Integration, IntegrationFn, - IntegrationFnResult, SanitizedRequestData, TracePropagationTargets, } from '@sentry/types'; @@ -124,9 +121,8 @@ const _httpIntegration = ((options: HttpIntegrationOptions = {}) => { shouldCreateSpanForRequest, }), }; - // eslint-disable-next-line deprecation/deprecation - return new Http(convertedOptions) as unknown as IntegrationFnResult; + return new Http(convertedOptions) as unknown as Integration; }) satisfies IntegrationFn; /** @@ -169,12 +165,9 @@ export class Http implements Integration { /** * @inheritDoc */ - public setupOnce( - _addGlobalEventProcessor: (callback: EventProcessor) => void, - setupOnceGetCurrentHub: () => Hub, - ): void { + public setupOnce(): void { // eslint-disable-next-line deprecation/deprecation - const clientOptions = setupOnceGetCurrentHub().getClient()?.getOptions(); + const clientOptions = getCurrentHub().getClient()?.getOptions(); // If `tracing` is not explicitly set, we default this based on whether or not tracing is enabled. // But for compatibility, we only do that if `enableIfHasTracingEnabled` is set. diff --git a/packages/node/src/integrations/undici/index.ts b/packages/node/src/integrations/undici/index.ts index 540776adf8d8..2a0ea01fe234 100644 --- a/packages/node/src/integrations/undici/index.ts +++ b/packages/node/src/integrations/undici/index.ts @@ -13,14 +13,7 @@ import { setHttpStatus, spanToTraceHeader, } from '@sentry/core'; -import type { - EventProcessor, - Integration, - IntegrationFn, - IntegrationFnResult, - Span, - SpanAttributes, -} from '@sentry/types'; +import type { Integration, IntegrationFn, Span, SpanAttributes } from '@sentry/types'; import { LRUMap, dynamicSamplingContextToSentryBaggageHeader, @@ -82,7 +75,7 @@ export interface UndiciOptions { const _nativeNodeFetchintegration = ((options?: Partial) => { // eslint-disable-next-line deprecation/deprecation - return new Undici(options) as unknown as IntegrationFnResult; + return new Undici(options) as unknown as Integration; }) satisfies IntegrationFn; export const nativeNodeFetchintegration = defineIntegration(_nativeNodeFetchintegration); @@ -125,7 +118,7 @@ export class Undici implements Integration { /** * @inheritDoc */ - public setupOnce(_addGlobalEventProcessor: (callback: EventProcessor) => void): void { + public setupOnce(): void { // Requires Node 16+ to use the diagnostics_channel API. if (NODE_VERSION.major < 16) { return; diff --git a/packages/node/test/integrations/contextlines.test.ts b/packages/node/test/integrations/contextlines.test.ts index dcc50f34c9a4..67f3ad793fbc 100644 --- a/packages/node/test/integrations/contextlines.test.ts +++ b/packages/node/test/integrations/contextlines.test.ts @@ -1,5 +1,5 @@ import * as fs from 'fs'; -import type { Event, IntegrationFnResult, StackFrame } from '@sentry/types'; +import type { Event, Integration, StackFrame } from '@sentry/types'; import { parseStackFrames } from '@sentry/utils'; import { contextLinesIntegration } from '../../src'; @@ -9,10 +9,10 @@ import { getError } from '../helper/error'; describe('ContextLines', () => { let readFileSpy: jest.SpyInstance; - let contextLines: IntegrationFnResult; + let contextLines: Integration; async function addContext(frames: StackFrame[]): Promise { - await (contextLines as IntegrationFnResult & { processEvent: (event: Event) => Promise }).processEvent({ + await (contextLines as Integration & { processEvent: (event: Event) => Promise }).processEvent({ exception: { values: [{ stacktrace: { frames } }] }, }); } @@ -101,7 +101,6 @@ describe('ContextLines', () => { }); test('parseStack with no context', async () => { - // eslint-disable-next-line deprecation/deprecation contextLines = contextLinesIntegration({ frameContextLines: 0 }); expect.assertions(1); @@ -114,7 +113,6 @@ describe('ContextLines', () => { test('does not attempt to readfile multiple times if it fails', async () => { expect.assertions(1); - // eslint-disable-next-line deprecation/deprecation contextLines = contextLinesIntegration(); readFileSpy.mockImplementation(() => { diff --git a/packages/node/test/integrations/http.test.ts b/packages/node/test/integrations/http.test.ts index 00e642ae6e10..3b1fa4904f04 100644 --- a/packages/node/test/integrations/http.test.ts +++ b/packages/node/test/integrations/http.test.ts @@ -1,7 +1,6 @@ import * as http from 'http'; import * as https from 'https'; -import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getSpanDescendants, startSpan } from '@sentry/core'; -import type { Hub } from '@sentry/core'; +import { SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, getSpanDescendants, makeMain, startSpan } from '@sentry/core'; import { getCurrentHub, getIsolationScope, setCurrentClient } from '@sentry/core'; import { Transaction } from '@sentry/core'; import { getCurrentScope, setUser, spanToJSON, startInactiveSpan } from '@sentry/core'; @@ -346,7 +345,11 @@ describe('tracing', () => { setCurrentClient(client); client.init(); // eslint-disable-next-line deprecation/deprecation - return getCurrentHub(); + const hub = getCurrentHub(); + // eslint-disable-next-line deprecation/deprecation + makeMain(hub); + + return hub; } function createTransactionAndPutOnScope() { @@ -365,12 +368,9 @@ describe('tracing', () => { // eslint-disable-next-line deprecation/deprecation const httpIntegration = new HttpIntegration({ tracing: true }); - const hub = createHub({ shouldCreateSpanForRequest: () => false }); + createHub({ shouldCreateSpanForRequest: () => false }); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); const transaction = createTransactionAndPutOnScope(); @@ -412,12 +412,9 @@ describe('tracing', () => { // eslint-disable-next-line deprecation/deprecation const httpIntegration = new HttpIntegration({ tracing: true }); - const hub = createHub({ tracePropagationTargets }); + createHub({ tracePropagationTargets }); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); createTransactionAndPutOnScope(); @@ -445,12 +442,9 @@ describe('tracing', () => { // eslint-disable-next-line deprecation/deprecation const httpIntegration = new HttpIntegration({ tracing: true }); - const hub = createHub({ tracePropagationTargets }); + createHub({ tracePropagationTargets }); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); createTransactionAndPutOnScope(); @@ -474,12 +468,9 @@ describe('tracing', () => { }, }); - const hub = createHub(); + createHub(); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); const transaction = createTransactionAndPutOnScope(); @@ -521,12 +512,9 @@ describe('tracing', () => { // eslint-disable-next-line deprecation/deprecation const httpIntegration = new HttpIntegration({ tracing: { tracePropagationTargets } }); - const hub = createHub(); + createHub(); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); createTransactionAndPutOnScope(); @@ -554,12 +542,9 @@ describe('tracing', () => { // eslint-disable-next-line deprecation/deprecation const httpIntegration = new HttpIntegration({ tracing: { tracePropagationTargets } }); - const hub = createHub(); + createHub(); - httpIntegration.setupOnce( - () => undefined, - () => hub as Hub, - ); + httpIntegration.setupOnce(); createTransactionAndPutOnScope(); diff --git a/packages/tracing-internal/src/node/integrations/express.ts b/packages/tracing-internal/src/node/integrations/express.ts index 430a72faa5a3..26c82a2ef8dd 100644 --- a/packages/tracing-internal/src/node/integrations/express.ts +++ b/packages/tracing-internal/src/node/integrations/express.ts @@ -121,7 +121,7 @@ export class Express implements Integration { /** * @inheritDoc */ - public setupOnce(_: unknown): void { + public setupOnce(): void { if (!this._router) { DEBUG_BUILD && logger.error('ExpressIntegration is missing an Express instance'); return; diff --git a/packages/tracing-internal/src/node/integrations/mongo.ts b/packages/tracing-internal/src/node/integrations/mongo.ts index 7c6f1bf97159..b85e0f3ae03a 100644 --- a/packages/tracing-internal/src/node/integrations/mongo.ts +++ b/packages/tracing-internal/src/node/integrations/mongo.ts @@ -1,6 +1,6 @@ import { SEMANTIC_ATTRIBUTE_SENTRY_ORIGIN, startInactiveSpan } from '@sentry/core'; import { getClient } from '@sentry/core'; -import type { EventProcessor, SpanAttributes, StartSpanOptions } from '@sentry/types'; +import type { SpanAttributes, StartSpanOptions } from '@sentry/types'; import { fill, isThenable, loadModule, logger } from '@sentry/utils'; import { DEBUG_BUILD } from '../../common/debug-build'; @@ -139,7 +139,7 @@ export class Mongo implements LazyLoadedIntegration { /** * @inheritDoc */ - public setupOnce(_: (callback: EventProcessor) => void): void { + public setupOnce(): void { const pkg = this.loadDependency(); if (!pkg) { diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 3c6c3a6fe8a4..9b8009de4fc4 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -52,7 +52,7 @@ export type { EventProcessor } from './eventprocessor'; export type { Exception } from './exception'; export type { Extra, Extras } from './extra'; export type { Hub } from './hub'; -export type { Integration, IntegrationClass, IntegrationFn, IntegrationFnResult } from './integration'; +export type { Integration, IntegrationClass, IntegrationFn } from './integration'; export type { Mechanism } from './mechanism'; export type { ExtractedNodeRequestData, HttpHeaderValue, Primitive, WorkerLocation } from './misc'; export type { ClientOptions, Options } from './options'; diff --git a/packages/types/src/integration.ts b/packages/types/src/integration.ts index 543238ccc07b..af54d389a3fd 100644 --- a/packages/types/src/integration.ts +++ b/packages/types/src/integration.ts @@ -1,7 +1,5 @@ import type { Client } from './client'; import type { Event, EventHint } from './event'; -import type { EventProcessor } from './eventprocessor'; -import type { Hub } from './hub'; /** Integration Class Interface */ export interface IntegrationClass { @@ -13,9 +11,8 @@ export interface IntegrationClass { new (...args: any[]): T; } -/** Integration interface. - * This is more or less the same as `Integration`, but with a slimmer `setupOnce` siganture. */ -export interface IntegrationFnResult { +/** Integration interface */ +export interface Integration { /** * The name of the integration. */ @@ -60,46 +57,4 @@ export interface IntegrationFnResult { * An integration in function form. * This is expected to return an integration. */ -export type IntegrationFn = (...rest: any[]) => IntegrationFnResult; - -/** Integration interface */ -export interface Integration { - /** - * The name of the integration. - */ - name: string; - - /** - * This hook is only called once, even if multiple clients are created. - * It does not receives any arguments, and should only use for e.g. global monkey patching and similar things. - */ - setupOnce?(addGlobalEventProcessor: (callback: EventProcessor) => void, getCurrentHub: () => Hub): void; - - /** - * Set up an integration for the given client. - * Receives the client as argument. - * - * Whenever possible, prefer this over `setupOnce`, as that is only run for the first client, - * whereas `setup` runs for each client. Only truly global things (e.g. registering global handlers) - * should be done in `setupOnce`. - */ - setup?(client: Client): void; - - /** - * This hook is triggered after `setupOnce()` and `setup()` have been called for all integrations. - * You can use it if it is important that all other integrations have been run before. - */ - afterAllSetup?(client: Client): void; - - /** - * An optional hook that allows to preprocess an event _before_ it is passed to all other event processors. - */ - preprocessEvent?(event: Event, hint: EventHint | undefined, client: Client): void; - - /** - * An optional hook that allows to process an event. - * Return `null` to drop the event, or mutate the event & return it. - * This receives the client that the integration was installed for as third argument. - */ - processEvent?(event: Event, hint: EventHint, client: Client): Event | null | PromiseLike; -} +export type IntegrationFn = (...rest: any[]) => Integration; From c75f93ef1c016ca44aa836570ff26f68886015e2 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Fri, 22 Mar 2024 17:16:37 -0400 Subject: [PATCH 07/39] chore: Add angular note to 8.0.0-alpha.5 changelog (#11254) Feedback from Bruno. Also went ahead and updated https://github.com/getsentry/sentry-javascript/releases/tag/8.0.0-alpha.5 accordingly. --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ce787aa60f3..4ab2ec10eabe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,12 @@ files. Instead, please initialize the Sentry Next.js SDK for the serverside in a In addition, the Next.js SDK now requires a minimum Next.js version of `13.2.0`. +- **feat(v8/angular): Merge angular and angular-ivy packages and start Angular support at v14 (#11091)** + +The `@sentry/angular-ivy` package has been removed. The `@sentry/angular` package now supports Ivy by default and +requires at least Angular 14. See the [Migration Guide](./MIGRATION.md#removal-of-sentryangular-ivy-package) for more +details. + ### Removal/Refactoring of deprecated functionality - feat(aws-serverless): Remove deprecated `rethrowAfterCapture` option (#11126) From 2774d1a4462efe488e4f8b9f6c5c13d5dd338968 Mon Sep 17 00:00:00 2001 From: Francesco Novy Date: Mon, 25 Mar 2024 12:21:18 +0000 Subject: [PATCH 08/39] feat(node): Do not include `prismaIntegration` by default (#11265) This seems to have issues in ESM builds (not just in astro, but also saw it in remix), so for now removing this from defaults - users can still add it manually if needed. We may find a better solution for this before v8 is stable. --- .../suites/tracing-experimental/prisma-orm/scenario.js | 1 + packages/astro/src/server/sdk.ts | 4 ---- .../node-experimental/src/integrations/tracing/index.ts | 6 ++++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing-experimental/prisma-orm/scenario.js b/dev-packages/node-integration-tests/suites/tracing-experimental/prisma-orm/scenario.js index 58b46ac1cf3a..7f291290bea2 100644 --- a/dev-packages/node-integration-tests/suites/tracing-experimental/prisma-orm/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing-experimental/prisma-orm/scenario.js @@ -9,6 +9,7 @@ Sentry.init({ release: '1.0', tracesSampleRate: 1.0, transport: loggingTransport, + integrations: [Sentry.prismaIntegration()], }); // Stop the process from exiting before the transaction is sent diff --git a/packages/astro/src/server/sdk.ts b/packages/astro/src/server/sdk.ts index a34a33cad31d..c2398c7d019f 100644 --- a/packages/astro/src/server/sdk.ts +++ b/packages/astro/src/server/sdk.ts @@ -1,6 +1,5 @@ import { applySdkMetadata } from '@sentry/core'; import type { NodeOptions } from '@sentry/node'; -import { getDefaultIntegrations } from '@sentry/node'; import { init as initNodeSdk, setTag } from '@sentry/node'; /** @@ -10,9 +9,6 @@ import { init as initNodeSdk, setTag } from '@sentry/node'; export function init(options: NodeOptions): void { const opts = { ...options, - // TODO v8: For now, we disable the Prisma integration, because that has weird esm-cjs interop issues - // We should figure these out and fix these before v8 goes stable. - defaultIntegrations: getDefaultIntegrations(options).filter(integration => integration.name !== 'Prisma'), }; applySdkMetadata(opts, 'astro', ['astro', 'node']); diff --git a/packages/node-experimental/src/integrations/tracing/index.ts b/packages/node-experimental/src/integrations/tracing/index.ts index ce3773fec1eb..85a72dac28c7 100644 --- a/packages/node-experimental/src/integrations/tracing/index.ts +++ b/packages/node-experimental/src/integrations/tracing/index.ts @@ -11,7 +11,6 @@ import { mysqlIntegration } from './mysql'; import { mysql2Integration } from './mysql2'; import { nestIntegration } from './nest'; import { postgresIntegration } from './postgres'; -import { prismaIntegration } from './prisma'; /** * With OTEL, all performance integrations will be added, as OTEL only initializes them when the patched package is actually required. @@ -26,7 +25,10 @@ export function getAutoPerformanceIntegrations(): Integration[] { mysqlIntegration(), mysql2Integration(), postgresIntegration(), - prismaIntegration(), + // For now, we do not include prisma by default because it has ESM issues + // See https://github.com/prisma/prisma/issues/23410 + // TODO v8: Figure out a better solution for this, maybe only disable in ESM mode? + // prismaIntegration(), nestIntegration(), hapiIntegration(), koaIntegration(), From 32b6a9980b4a6cb9dd123c70e9eff1ec218913f2 Mon Sep 17 00:00:00 2001 From: Sigrid Huemer <32902192+s1gr1d@users.noreply.github.com> Date: Mon, 25 Mar 2024 13:23:31 +0100 Subject: [PATCH 09/39] fix(nextjs): Show misconfiguration warning (no `instrumentation.ts`) (#11266) The warning existed, but was not called --- packages/nextjs/src/config/webpack.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/nextjs/src/config/webpack.ts b/packages/nextjs/src/config/webpack.ts index 2e7c8bb57a80..68223b7e6b9e 100644 --- a/packages/nextjs/src/config/webpack.ts +++ b/packages/nextjs/src/config/webpack.ts @@ -60,6 +60,10 @@ export function constructWebpackConfigFunction( const { isServer, dev: isDev, dir: projectDir } = buildContext; const runtime = isServer ? (buildContext.nextRuntime === 'edge' ? 'edge' : 'server') : 'client'; + if (runtime !== 'client') { + warnAboutDeprecatedConfigFiles(projectDir, runtime); + } + let rawNewConfig = { ...incomingConfig }; // if user has custom webpack config (which always takes the form of a function), run it so we have actual values to @@ -508,25 +512,23 @@ async function addSentryToClientEntryProperty( * Searches for old `sentry.(server|edge).config.ts` files and warns if it finds any. * * @param projectDir The root directory of the project, where config files would be located - * @param platform Either "server", "client" or "edge", so that we know which file to look for + * @param platform Either "server" or "edge", so that we know which file to look for */ -export function warnAboutDeprecatedConfigFiles(projectDir: string, platform: 'server' | 'client' | 'edge'): void { +function warnAboutDeprecatedConfigFiles(projectDir: string, platform: 'server' | 'edge'): void { const possibilities = [`sentry.${platform}.config.ts`, `sentry.${platform}.config.js`]; for (const filename of possibilities) { if (fs.existsSync(path.resolve(projectDir, filename))) { - if (platform === 'server' || platform === 'edge') { - // eslint-disable-next-line no-console - console.warn( - `[@sentry/nextjs] It seems you have configured a \`${filename}\` file. You need to put this file's content into a Next.js instrumentation hook instead! Read more: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation`, - ); - } + // eslint-disable-next-line no-console + console.warn( + `[@sentry/nextjs] It appears you've configured a \`${filename}\` file. Please ensure to put this file's content into the \`register()\` function of a Next.js instrumentation hook instead. To ensure correct functionality of the SDK, \`Sentry.init\` must be called inside \`instrumentation.ts\`. Learn more about setting up an instrumentation hook in Next.js: https://nextjs.org/docs/app/building-your-application/optimizing/instrumentation. You can safely delete the \`${filename}\` file afterward.`, + ); } } } /** - * Searches for a `sentry.client.config.ts|js` file and returns it's file name if it finds one. (ts being prioritized) + * Searches for a `sentry.client.config.ts|js` file and returns its file name if it finds one. (ts being prioritized) * * @param projectDir The root directory of the project, where config files would be located */ From 284e90dfc70f4a161c41cb952d831d18162b9801 Mon Sep 17 00:00:00 2001 From: Luca Forstner Date: Mon, 25 Mar 2024 14:25:37 +0100 Subject: [PATCH 10/39] fix(opentelemetry): Do not stomp span status when `startSpan` callback throws (#11170) --- packages/core/src/utils/spanUtils.ts | 8 +++----- packages/opentelemetry/src/spanExporter.ts | 4 ++-- packages/opentelemetry/src/trace.ts | 11 +++++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/packages/core/src/utils/spanUtils.ts b/packages/core/src/utils/spanUtils.ts index 094f6674121c..8478778d7dd5 100644 --- a/packages/core/src/utils/spanUtils.ts +++ b/packages/core/src/utils/spanUtils.ts @@ -85,12 +85,10 @@ function ensureTimestampInSeconds(timestamp: number): number { /** * Convert a span to a JSON representation. - * Note that all fields returned here are optional and need to be guarded against. - * - * Note: Because of this, we currently have a circular type dependency (which we opted out of in package.json). - * This is not avoidable as we need `spanToJSON` in `spanUtils.ts`, which in turn is needed by `span.ts` for backwards compatibility. - * And `spanToJSON` needs the Span class from `span.ts` to check here. */ +// Note: Because of this, we currently have a circular type dependency (which we opted out of in package.json). +// This is not avoidable as we need `spanToJSON` in `spanUtils.ts`, which in turn is needed by `span.ts` for backwards compatibility. +// And `spanToJSON` needs the Span class from `span.ts` to check here. export function spanToJSON(span: Span): Partial { if (spanIsSentrySpan(span)) { return span.getSpanJSON(); diff --git a/packages/opentelemetry/src/spanExporter.ts b/packages/opentelemetry/src/spanExporter.ts index 58f6ba53303e..75c0c8be5ed9 100644 --- a/packages/opentelemetry/src/spanExporter.ts +++ b/packages/opentelemetry/src/spanExporter.ts @@ -178,7 +178,7 @@ function createTransactionForOtelSpan(span: ReadableSpan): TransactionEvent { data: attributes, origin, op, - status: getStatusMessage(status), + status: getStatusMessage(status), // As per protocol, span status is allowed to be undefined }); const transactionEvent: TransactionEvent = { @@ -252,7 +252,7 @@ function createAndFinishSpanForOtelSpan(node: SpanNode, spans: SpanJSON[], remai start_timestamp: convertOtelTimeToSeconds(startTime), // This is [0,0] by default in OTEL, in which case we want to interpret this as no end time timestamp: convertOtelTimeToSeconds(endTime) || undefined, - status: getStatusMessage(status), + status: getStatusMessage(status), // As per protocol, span status is allowed to be undefined op, origin, _metrics_summary: getMetricSummaryJsonForSpan(span as unknown as Span), diff --git a/packages/opentelemetry/src/trace.ts b/packages/opentelemetry/src/trace.ts index 945e60a811f1..d47c8db5ec2b 100644 --- a/packages/opentelemetry/src/trace.ts +++ b/packages/opentelemetry/src/trace.ts @@ -12,6 +12,7 @@ import { getDynamicSamplingContextFromClient, getRootSpan, handleCallbackErrors, + spanToJSON, } from '@sentry/core'; import type { Client, Scope } from '@sentry/types'; import { continueTraceAsRemoteSpan, getSamplingDecision, makeTraceState } from './propagator'; @@ -46,7 +47,10 @@ export function startSpan(options: OpenTelemetrySpanContext, callback: (span: return handleCallbackErrors( () => callback(span), () => { - span.setStatus({ code: SpanStatusCode.ERROR }); + // Only set the span status to ERROR when there wasn't any status set before, in order to avoid stomping useful span statuses + if (spanToJSON(span).status === undefined) { + span.setStatus({ code: SpanStatusCode.ERROR }); + } }, () => span.end(), ); @@ -82,7 +86,10 @@ export function startSpanManual( return handleCallbackErrors( () => callback(span, () => span.end()), () => { - span.setStatus({ code: SpanStatusCode.ERROR }); + // Only set the span status to ERROR when there wasn't any status set before, in order to avoid stomping useful span statuses + if (spanToJSON(span).status === undefined) { + span.setStatus({ code: SpanStatusCode.ERROR }); + } }, ); }); From a8e28eb0984de27f48f92d85a44b2fde84333f7e Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 25 Mar 2024 09:58:43 -0400 Subject: [PATCH 11/39] feat(v8): Remove deprecated span id fields (#11180) ref https://github.com/getsentry/sentry-javascript/issues/10100 Removes `span.spanId`, `span.traceId`, and `span.parentSpanId`. --- .../sentry-trace/baggage-header-out/server.ts | 9 ++-- .../sentry-trace/baggage-header-out/test.ts | 2 +- .../baggage-transaction-name/server.ts | 8 +-- packages/core/src/tracing/sentrySpan.ts | 50 ------------------- .../core/test/lib/tracing/sentrySpan.test.ts | 27 +++++++--- packages/node/test/handlers.test.ts | 30 ++++++----- packages/types/src/envelope.ts | 3 +- packages/types/src/transaction.ts | 14 +----- 8 files changed, 45 insertions(+), 98 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/server.ts b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/server.ts index 64f697ca086c..e849eca7b9f2 100644 --- a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/server.ts +++ b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/server.ts @@ -28,12 +28,11 @@ app.use(cors()); app.get('/test/express', (_req, res) => { // eslint-disable-next-line deprecation/deprecation const transaction = Sentry.getCurrentScope().getTransaction(); - if (transaction) { - // eslint-disable-next-line deprecation/deprecation - transaction.traceId = '86f39e84263a4de99c326acab3bfe3bd'; - } + const traceId = transaction?.spanContext().traceId; const headers = http.get('http://somewhere.not.sentry/').getHeaders(); - + if (traceId) { + headers['baggage'] = (headers['baggage'] as string).replace(traceId, '__SENTRY_TRACE_ID__'); + } // Responding with the headers outgoing request headers back to the assertions. res.send({ test_data: headers }); }); diff --git a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/test.ts b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/test.ts index 3cd2e9984685..c3add50d89cd 100644 --- a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/test.ts +++ b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-header-out/test.ts @@ -16,7 +16,7 @@ test('should attach a baggage header to an outgoing request.', async () => { host: 'somewhere.not.sentry', baggage: 'sentry-environment=prod,sentry-release=1.0,sentry-public_key=public' + - ',sentry-trace_id=86f39e84263a4de99c326acab3bfe3bd,sentry-sample_rate=1,sentry-transaction=GET%20%2Ftest%2Fexpress' + + ',sentry-trace_id=__SENTRY_TRACE_ID__,sentry-sample_rate=1,sentry-transaction=GET%20%2Ftest%2Fexpress' + ',sentry-sampled=true', }, }); diff --git a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-transaction-name/server.ts b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-transaction-name/server.ts index 8616908dd6d5..2e5cfedb8046 100644 --- a/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-transaction-name/server.ts +++ b/dev-packages/node-integration-tests/suites/express/sentry-trace/baggage-transaction-name/server.ts @@ -32,13 +32,9 @@ app.use(cors()); app.get('/test/express', (_req, res) => { // eslint-disable-next-line deprecation/deprecation const transaction = Sentry.getCurrentScope().getTransaction(); - if (transaction) { - // eslint-disable-next-line deprecation/deprecation - transaction.traceId = '86f39e84263a4de99c326acab3bfe3bd'; - transaction.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); - } - const headers = http.get('http://somewhere.not.sentry/').getHeaders(); + transaction?.setAttribute(SEMANTIC_ATTRIBUTE_SENTRY_SOURCE, 'route'); + const headers = http.get('http://somewhere.not.sentry/').getHeaders(); // Responding with the headers outgoing request headers back to the assertions. res.send({ test_data: headers }); }); diff --git a/packages/core/src/tracing/sentrySpan.ts b/packages/core/src/tracing/sentrySpan.ts index 87b57d729960..68570997131d 100644 --- a/packages/core/src/tracing/sentrySpan.ts +++ b/packages/core/src/tracing/sentrySpan.ts @@ -97,56 +97,6 @@ export class SentrySpan implements Span { // This rule conflicts with another eslint rule :( /* eslint-disable @typescript-eslint/member-ordering */ - /** - * The ID of the trace. - * @deprecated Use `spanContext().traceId` instead. - */ - public get traceId(): string { - return this._traceId; - } - - /** - * The ID of the trace. - * @deprecated You cannot update the traceId of a span after span creation. - */ - public set traceId(traceId: string) { - this._traceId = traceId; - } - - /** - * The ID of the span. - * @deprecated Use `spanContext().spanId` instead. - */ - public get spanId(): string { - return this._spanId; - } - - /** - * The ID of the span. - * @deprecated You cannot update the spanId of a span after span creation. - */ - public set spanId(spanId: string) { - this._spanId = spanId; - } - - /** - * @inheritDoc - * - * @deprecated Use `startSpan` functions instead. - */ - public set parentSpanId(string) { - this._parentSpanId = string; - } - - /** - * @inheritDoc - * - * @deprecated Use `spanToJSON(span).parent_span_id` instead. - */ - public get parentSpanId(): string | undefined { - return this._parentSpanId; - } - /** * Was this span chosen to be sent as part of the sample? * @deprecated Use `isRecording()` instead. diff --git a/packages/core/test/lib/tracing/sentrySpan.test.ts b/packages/core/test/lib/tracing/sentrySpan.test.ts index e065aeff33aa..e7a971d0bdcf 100644 --- a/packages/core/test/lib/tracing/sentrySpan.test.ts +++ b/packages/core/test/lib/tracing/sentrySpan.test.ts @@ -1,7 +1,13 @@ import { timestampInSeconds } from '@sentry/utils'; import { SentrySpan } from '../../../src/tracing/sentrySpan'; import { SPAN_STATUS_ERROR } from '../../../src/tracing/spanstatus'; -import { TRACE_FLAG_NONE, TRACE_FLAG_SAMPLED, spanToJSON, spanToTraceContext } from '../../../src/utils/spanUtils'; +import { + TRACE_FLAG_NONE, + TRACE_FLAG_SAMPLED, + spanIsSampled, + spanToJSON, + spanToTraceContext, +} from '../../../src/utils/spanUtils'; describe('SentrySpan', () => { describe('name', () => { @@ -25,9 +31,9 @@ describe('SentrySpan', () => { const span = new SentrySpan({ sampled: true }); // eslint-disable-next-line deprecation/deprecation const span2 = span.startChild(); - expect((span2 as any).parentSpanId).toBe((span as any).spanId); - expect((span2 as any).traceId).toBe((span as any).traceId); - expect((span2 as any).sampled).toBe((span as any).sampled); + expect(spanToJSON(span2).parent_span_id).toBe(span.spanContext().spanId); + expect(span.spanContext().traceId).toBe(span.spanContext().traceId); + expect(spanIsSampled(span2)).toBe(spanIsSampled(span)); }); }); @@ -58,8 +64,13 @@ describe('SentrySpan', () => { }); test('with parent', () => { - const spanA = new SentrySpan({ traceId: 'a', spanId: 'b' }) as any; - const spanB = new SentrySpan({ traceId: 'c', spanId: 'd', sampled: false, parentSpanId: spanA.spanId }); + const spanA = new SentrySpan({ traceId: 'a', spanId: 'b' }); + const spanB = new SentrySpan({ + traceId: 'c', + spanId: 'd', + sampled: false, + parentSpanId: spanA.spanContext().spanId, + }); const serialized = spanToJSON(spanB); expect(serialized).toHaveProperty('parent_span_id', 'b'); expect(serialized).toHaveProperty('span_id', 'd'); @@ -67,9 +78,9 @@ describe('SentrySpan', () => { }); test('should drop all `undefined` values', () => { - const spanA = new SentrySpan({ traceId: 'a', spanId: 'b' }) as any; + const spanA = new SentrySpan({ traceId: 'a', spanId: 'b' }); const spanB = new SentrySpan({ - parentSpanId: spanA.spanId, + parentSpanId: spanA.spanContext().spanId, spanId: 'd', traceId: 'c', }); diff --git a/packages/node/test/handlers.test.ts b/packages/node/test/handlers.test.ts index 8a84cffd758a..239b79c52564 100644 --- a/packages/node/test/handlers.test.ts +++ b/packages/node/test/handlers.test.ts @@ -9,6 +9,7 @@ import { getMainCarrier, mergeScopeData, setCurrentClient, + spanIsSampled, spanToJSON, withScope, } from '@sentry/core'; @@ -289,7 +290,7 @@ describe('tracingHandler', () => { sentryTracingMiddleware(req, res, next); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; expect(getPropagationContext()).toEqual({ traceId: '12312012123120121231201212312012', @@ -300,9 +301,10 @@ describe('tracingHandler', () => { }); // since we have no tracesSampler defined, the default behavior (inherit if possible) applies - expect(transaction.traceId).toEqual('12312012123120121231201212312012'); - expect(transaction.parentSpanId).toEqual('1121201211212012'); - expect(transaction.sampled).toEqual(false); + expect(transaction.spanContext().traceId).toEqual('12312012123120121231201212312012'); + expect(spanToJSON(transaction).parent_span_id).toEqual('1121201211212012'); + expect(spanIsSampled(transaction)).toEqual(false); + // eslint-disable-next-line deprecation/deprecation expect(transaction.metadata?.dynamicSamplingContext).toStrictEqual({}); }); @@ -322,12 +324,13 @@ describe('tracingHandler', () => { dsc: { version: '1.0', environment: 'production' }, }); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; // since we have no tracesSampler defined, the default behavior (inherit if possible) applies - expect(transaction.traceId).toEqual('12312012123120121231201212312012'); - expect(transaction.parentSpanId).toEqual('1121201211212012'); - expect(transaction.sampled).toEqual(true); + expect(transaction.spanContext().traceId).toEqual('12312012123120121231201212312012'); + expect(spanToJSON(transaction).parent_span_id).toEqual('1121201211212012'); + expect(spanIsSampled(transaction)).toEqual(true); + // eslint-disable-next-line deprecation/deprecation expect(transaction.metadata?.dynamicSamplingContext).toStrictEqual({ version: '1.0', environment: 'production' }); }); @@ -341,7 +344,8 @@ describe('tracingHandler', () => { expect(getPropagationContext().dsc).toEqual({ version: '1.0', environment: 'production' }); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; + // eslint-disable-next-line deprecation/deprecation expect(transaction.metadata?.dynamicSamplingContext).toStrictEqual({ version: '1.0', environment: 'production' }); }); @@ -364,7 +368,7 @@ describe('tracingHandler', () => { it('puts its transaction on the response object', () => { sentryTracingMiddleware(req, res, next); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; expect(transaction).toBeDefined(); @@ -396,7 +400,7 @@ describe('tracingHandler', () => { sentryTracingMiddleware(req, res, next); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; expect(spanToJSON(transaction).description).toBe(`${method.toUpperCase()} ${path}`); }); @@ -406,7 +410,7 @@ describe('tracingHandler', () => { sentryTracingMiddleware(req, res, next); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; expect(spanToJSON(transaction).description).toBe(`${method.toUpperCase()} ${path}`); }); @@ -416,7 +420,7 @@ describe('tracingHandler', () => { sentryTracingMiddleware(req, res, next); - const transaction = (res as any).__sentry_transaction; + const transaction = (res as any).__sentry_transaction as Transaction; expect(spanToJSON(transaction).description).toBe(`${method.toUpperCase()} ${path}`); }); diff --git a/packages/types/src/envelope.ts b/packages/types/src/envelope.ts index 721c13323bdb..7a9ad2e4d5c3 100644 --- a/packages/types/src/envelope.ts +++ b/packages/types/src/envelope.ts @@ -8,13 +8,12 @@ import type { Profile } from './profiling'; import type { ReplayEvent, ReplayRecordingData } from './replay'; import type { SdkInfo } from './sdkinfo'; import type { SerializedSession, Session, SessionAggregates } from './session'; -import type { Transaction } from './transaction'; // Based on: https://develop.sentry.dev/sdk/envelopes/ // Based on https://github.com/getsentry/relay/blob/b23b8d3b2360a54aaa4d19ecae0231201f31df5e/relay-sampling/src/lib.rs#L685-L707 export type DynamicSamplingContext = { - trace_id: Transaction['traceId']; + trace_id: string; public_key: DsnComponents['publicKey']; sample_rate?: string; release?: string; diff --git a/packages/types/src/transaction.ts b/packages/types/src/transaction.ts index be482a2c196e..533401455488 100644 --- a/packages/types/src/transaction.ts +++ b/packages/types/src/transaction.ts @@ -57,19 +57,7 @@ export interface TraceparentData { /** * Transaction "Class", inherits Span only has `setName` */ -export interface Transaction extends Omit, Span { - /** - * The ID of the transaction. - * @deprecated Use `spanContext().spanId` instead. - */ - spanId: string; - - /** - * The ID of the trace. - * @deprecated Use `spanContext().traceId` instead. - */ - traceId: string; - +export interface Transaction extends Omit, Span { /** * Was this transaction chosen to be sent as part of the sample? * @deprecated Use `spanIsSampled(transaction)` instead. From 000005595188ef214d2115803d1329469f1e114d Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 25 Mar 2024 10:06:35 -0400 Subject: [PATCH 12/39] feat(v8): Remove addGlobalEventProcessor (#11255) ref https://github.com/getsentry/sentry-javascript/issues/10100 Removes `addGlobalEventProcessor` and adds migration guide. --- MIGRATION.md | 25 +++++++++++++++++-- packages/browser/src/exports.ts | 2 -- packages/core/src/eventProcessors.ts | 19 +------------- packages/core/src/index.ts | 6 +---- packages/core/src/utils/prepareEvent.ts | 7 +----- packages/node/src/index.ts | 2 -- .../test/mocks/resetSdkMock.ts | 4 +-- packages/utils/src/worldwide.ts | 1 - 8 files changed, 27 insertions(+), 39 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index e95de8d8be29..23ba5c4b4c25 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -355,7 +355,7 @@ To make sure these integrations work properly you'll have to change how you Removed top-level exports: `tracingOrigins`, `MetricsAggregator`, `metricsAggregatorIntegration`, `Severity`, `Sentry.configureScope`, `Span`, `spanStatusfromHttpCode`, `makeMain`, `lastEventId`, `pushScope`, `popScope`, -`addGlobalEventProcessor`, `timestampWithMs`, `addExtensionMethods` +`addGlobalEventProcessor`, `timestampWithMs`, `addExtensionMethods`, `addGlobalEventProcessor` Removed `@sentry/utils` exports: `timestampWithMs`, `addOrUpdateIntegration`, `tracingContextFromHeaders`, `walk` @@ -370,6 +370,7 @@ Removed `@sentry/utils` exports: `timestampWithMs`, `addOrUpdateIntegration`, `t - [Removal of `addGlobalEventProcessor` in favour of `addEventProcessor`](./MIGRATION.md#removal-of-addglobaleventprocessor-in-favour-of-addeventprocessor) - [Removal of `lastEventId()` method](./MIGRATION.md#deprecate-lasteventid) - [Remove `void` from transport return types](./MIGRATION.md#remove-void-from-transport-return-types) +- [Remove `addGlobalEventProcessor` in favor of `addEventProcessor`](./MIGRATION.md#remove-addglobaleventprocessor-in-favor-of-addeventprocessor) #### Deprecation of `Hub` and `getCurrentHub()` @@ -540,7 +541,7 @@ addGlobalEventProcessor(event => { ```js // v8 -addEventProcessor(event => { +Sentry.getGlobalScope().addEventProcessor(event => { delete event.extra; return event; }); @@ -569,6 +570,26 @@ interface Transport { } ``` +#### Remove `addGlobalEventProcessor` in favor of `addEventProcessor` + +In v8, we are removing the `addGlobalEventProcessor` function in favor of `addEventProcessor`. + +```js +// v7 +addGlobalEventProcessor(event => { + delete event.extra; + return event; +}); +``` + +```js +// v8 +addEventProcessor(event => { + delete event.extra; + return event; +}); +``` + ### Browser SDK (Browser, React, Vue, Angular, Ember, etc.) Removed top-level exports: `Offline`, `makeXHRTransport`, `BrowserTracing`, `wrap` diff --git a/packages/browser/src/exports.ts b/packages/browser/src/exports.ts index a4b10d5b6988..07fe2eda1c8c 100644 --- a/packages/browser/src/exports.ts +++ b/packages/browser/src/exports.ts @@ -20,8 +20,6 @@ export type { BrowserOptions } from './client'; export type { ReportDialogOptions } from './sdk'; export { - // eslint-disable-next-line deprecation/deprecation - addGlobalEventProcessor, addEventProcessor, addBreadcrumb, addIntegration, diff --git a/packages/core/src/eventProcessors.ts b/packages/core/src/eventProcessors.ts index 0f5e0f0202fa..2f648ba608e2 100644 --- a/packages/core/src/eventProcessors.ts +++ b/packages/core/src/eventProcessors.ts @@ -1,25 +1,8 @@ import type { Event, EventHint, EventProcessor } from '@sentry/types'; -import { SyncPromise, getGlobalSingleton, isThenable, logger } from '@sentry/utils'; +import { SyncPromise, isThenable, logger } from '@sentry/utils'; import { DEBUG_BUILD } from './debug-build'; -/** - * Returns the global event processors. - * @deprecated Global event processors will be removed in v8. - */ -export function getGlobalEventProcessors(): EventProcessor[] { - return getGlobalSingleton('globalEventProcessors', () => []); -} - -/** - * Add a EventProcessor to be kept globally. - * @deprecated Use `addEventProcessor` instead. Global event processors will be removed in v8. - */ -export function addGlobalEventProcessor(callback: EventProcessor): void { - // eslint-disable-next-line deprecation/deprecation - getGlobalEventProcessors().push(callback); -} - /** * Process an array of event processors, returning the processed event (or `null` if the event was dropped). */ diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 217ae7273422..c384701319ef 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -54,11 +54,7 @@ export { export { makeSession, closeSession, updateSession } from './session'; export { SessionFlusher } from './sessionflusher'; export { Scope } from './scope'; -export { - notifyEventProcessors, - // eslint-disable-next-line deprecation/deprecation - addGlobalEventProcessor, -} from './eventProcessors'; +export { notifyEventProcessors } from './eventProcessors'; export { getEnvelopeEndpointWithUrlEncodedAuth, getReportDialogEndpoint } from './api'; export { BaseClient } from './baseclient'; export { ServerRuntimeClient } from './server-runtime-client'; diff --git a/packages/core/src/utils/prepareEvent.ts b/packages/core/src/utils/prepareEvent.ts index 92cc5ffa65fa..6bc21cadbffa 100644 --- a/packages/core/src/utils/prepareEvent.ts +++ b/packages/core/src/utils/prepareEvent.ts @@ -13,7 +13,7 @@ import { GLOBAL_OBJ, addExceptionMechanism, dateTimestampInSeconds, normalize, t import { DEFAULT_ENVIRONMENT } from '../constants'; import { getGlobalScope } from '../currentScopes'; -import { getGlobalEventProcessors, notifyEventProcessors } from '../eventProcessors'; +import { notifyEventProcessors } from '../eventProcessors'; import { Scope } from '../scope'; import { applyScopeDataToEvent, mergeScopeData } from './applyScopeDataToEvent'; @@ -35,8 +35,6 @@ export type ExclusiveEventHintOrCaptureContext = * Information that is already present in the event is never overwritten. For * nested objects, such as the context, keys are merged. * - * Note: This also triggers callbacks for `addGlobalEventProcessor`, but not `beforeSend`. - * * @param event The original event. * @param hint May contain additional information about the original exception. * @param scope A scope containing event metadata. @@ -99,11 +97,8 @@ export function prepareEvent( applyScopeDataToEvent(prepared, data); - // TODO (v8): Update this order to be: Global > Client > Scope const eventProcessors = [ ...clientEventProcessors, - // eslint-disable-next-line deprecation/deprecation - ...getGlobalEventProcessors(), // Run scope event processors _after_ all other processors ...data.eventProcessors, ]; diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts index 73cd82c93b32..0184c14e730e 100644 --- a/packages/node/src/index.ts +++ b/packages/node/src/index.ts @@ -21,8 +21,6 @@ export type { AddRequestDataToEventOptions, TransactionNamingScheme } from '@sen export type { NodeOptions } from './types'; export { - // eslint-disable-next-line deprecation/deprecation - addGlobalEventProcessor, addEventProcessor, addBreadcrumb, addIntegration, diff --git a/packages/replay-internal/test/mocks/resetSdkMock.ts b/packages/replay-internal/test/mocks/resetSdkMock.ts index a8fdd97ef5ac..3596ad4d29d2 100644 --- a/packages/replay-internal/test/mocks/resetSdkMock.ts +++ b/packages/replay-internal/test/mocks/resetSdkMock.ts @@ -1,5 +1,4 @@ -import type { EventProcessor } from '@sentry/types'; -import { getGlobalSingleton, resetInstrumentationHandlers } from '@sentry/utils'; +import { resetInstrumentationHandlers } from '@sentry/utils'; import type { Replay as ReplayIntegration } from '../../src/integration'; import type { ReplayContainer } from '../../src/replay'; @@ -23,7 +22,6 @@ export async function resetSdkMock({ replayOptions, sentryOptions, autoStart }: // Clear all handlers that have been registered resetInstrumentationHandlers(); - getGlobalSingleton('globalEventProcessors', () => []).length = 0; const SentryUtils = await import('@sentry/utils'); jest.spyOn(SentryUtils, 'addClickKeypressInstrumentationHandler').mockImplementation(handler => { diff --git a/packages/utils/src/worldwide.ts b/packages/utils/src/worldwide.ts index dc6b59d6bff0..c1da12f85135 100644 --- a/packages/utils/src/worldwide.ts +++ b/packages/utils/src/worldwide.ts @@ -46,7 +46,6 @@ export interface InternalGlobal { */ _sentryDebugIds?: Record; __SENTRY__: { - globalEventProcessors: any; hub: any; logger: any; extensions?: { From 693f6ca9feb6135a7dadd3f36178ad44176f06c6 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Mon, 25 Mar 2024 14:54:24 +0000 Subject: [PATCH 13/39] feat(node): Add scope to ANR events (#11256) Closes #10668 Rather than inject large unchecked JavaScript strings to run via `Runtime.evaluate`, when the ANR integration is enabled, we add a function to `global.__SENTRY_GET_SCOPES__` which can then be called via the debugger when the event loop is suspended. --- .../suites/anr/basic-session.js | 3 ++ .../suites/anr/basic.js | 3 ++ .../suites/anr/basic.mjs | 3 ++ .../suites/anr/forked.js | 3 ++ .../suites/anr/isolated.mjs | 53 +++++++++++++++++++ .../suites/anr/stop-and-start.js | 3 ++ .../node-integration-tests/suites/anr/test.ts | 39 ++++++++++++++ .../src/integrations/anr/index.ts | 40 +++++++++++--- .../src/integrations/anr/worker.ts | 44 +++++++++++---- 9 files changed, 173 insertions(+), 18 deletions(-) create mode 100644 dev-packages/node-integration-tests/suites/anr/isolated.mjs diff --git a/dev-packages/node-integration-tests/suites/anr/basic-session.js b/dev-packages/node-integration-tests/suites/anr/basic-session.js index 153acf83f16f..5661e08b850b 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic-session.js +++ b/dev-packages/node-integration-tests/suites/anr/basic-session.js @@ -15,6 +15,9 @@ Sentry.init({ autoSessionTracking: true, }); +Sentry.setUser({ email: 'person@home.com' }); +Sentry.addBreadcrumb({ message: 'important message!' }); + function longWork() { for (let i = 0; i < 20; i++) { const salt = crypto.randomBytes(128).toString('base64'); diff --git a/dev-packages/node-integration-tests/suites/anr/basic.js b/dev-packages/node-integration-tests/suites/anr/basic.js index 712e0e26a3f8..d98b18216703 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic.js +++ b/dev-packages/node-integration-tests/suites/anr/basic.js @@ -15,6 +15,9 @@ Sentry.init({ integrations: [Sentry.anrIntegration({ captureStackTrace: true, anrThreshold: 100 })], }); +Sentry.setUser({ email: 'person@home.com' }); +Sentry.addBreadcrumb({ message: 'important message!' }); + function longWork() { for (let i = 0; i < 20; i++) { const salt = crypto.randomBytes(128).toString('base64'); diff --git a/dev-packages/node-integration-tests/suites/anr/basic.mjs b/dev-packages/node-integration-tests/suites/anr/basic.mjs index 0184ca9583f7..77bb9ae3626d 100644 --- a/dev-packages/node-integration-tests/suites/anr/basic.mjs +++ b/dev-packages/node-integration-tests/suites/anr/basic.mjs @@ -15,6 +15,9 @@ Sentry.init({ integrations: [Sentry.anrIntegration({ captureStackTrace: true, anrThreshold: 100 })], }); +Sentry.setUser({ email: 'person@home.com' }); +Sentry.addBreadcrumb({ message: 'important message!' }); + function longWork() { for (let i = 0; i < 20; i++) { const salt = crypto.randomBytes(128).toString('base64'); diff --git a/dev-packages/node-integration-tests/suites/anr/forked.js b/dev-packages/node-integration-tests/suites/anr/forked.js index 0db282eacb07..06529096cca5 100644 --- a/dev-packages/node-integration-tests/suites/anr/forked.js +++ b/dev-packages/node-integration-tests/suites/anr/forked.js @@ -15,6 +15,9 @@ Sentry.init({ integrations: [Sentry.anrIntegration({ captureStackTrace: true, anrThreshold: 100 })], }); +Sentry.setUser({ email: 'person@home.com' }); +Sentry.addBreadcrumb({ message: 'important message!' }); + function longWork() { for (let i = 0; i < 20; i++) { const salt = crypto.randomBytes(128).toString('base64'); diff --git a/dev-packages/node-integration-tests/suites/anr/isolated.mjs b/dev-packages/node-integration-tests/suites/anr/isolated.mjs new file mode 100644 index 000000000000..d9b179c63e71 --- /dev/null +++ b/dev-packages/node-integration-tests/suites/anr/isolated.mjs @@ -0,0 +1,53 @@ +import * as assert from 'assert'; +import * as crypto from 'crypto'; + +import * as Sentry from '@sentry/node'; + +setTimeout(() => { + process.exit(); +}, 10000); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + release: '1.0', + debug: true, + autoSessionTracking: false, + integrations: [Sentry.anrIntegration({ captureStackTrace: true, anrThreshold: 100 })], +}); + +async function longWork() { + await new Promise(resolve => setTimeout(resolve, 1000)); + + for (let i = 0; i < 20; i++) { + const salt = crypto.randomBytes(128).toString('base64'); + const hash = crypto.pbkdf2Sync('myPassword', salt, 10000, 512, 'sha512'); + assert.ok(hash); + } +} + +function neverResolve() { + return new Promise(() => { + // + }); +} + +const fns = [ + neverResolve, + neverResolve, + neverResolve, + neverResolve, + neverResolve, + longWork, // [5] + neverResolve, + neverResolve, + neverResolve, + neverResolve, +]; + +for (let id = 0; id < 10; id++) { + Sentry.withIsolationScope(async () => { + Sentry.setUser({ id }); + + await fns[id](); + }); +} diff --git a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js index 9de453abf23d..4f9fc9bc64db 100644 --- a/dev-packages/node-integration-tests/suites/anr/stop-and-start.js +++ b/dev-packages/node-integration-tests/suites/anr/stop-and-start.js @@ -17,6 +17,9 @@ Sentry.init({ integrations: [anr], }); +Sentry.setUser({ email: 'person@home.com' }); +Sentry.addBreadcrumb({ message: 'important message!' }); + function longWorkIgnored() { for (let i = 0; i < 20; i++) { const salt = crypto.randomBytes(128).toString('base64'); diff --git a/dev-packages/node-integration-tests/suites/anr/test.ts b/dev-packages/node-integration-tests/suites/anr/test.ts index 7ace974d6170..b0299f4a038d 100644 --- a/dev-packages/node-integration-tests/suites/anr/test.ts +++ b/dev-packages/node-integration-tests/suites/anr/test.ts @@ -21,6 +21,15 @@ const EXPECTED_ANR_EVENT = { timezone: expect.any(String), }, }, + user: { + email: 'person@home.com', + }, + breadcrumbs: [ + { + timestamp: expect.any(Number), + message: 'important message!', + }, + ], // and an exception that is our ANR exception: { values: [ @@ -105,4 +114,34 @@ conditionalTest({ min: 16 })('should report ANR when event loop blocked', () => test('worker can be stopped and restarted', done => { createRunner(__dirname, 'stop-and-start.js').expect({ event: EXPECTED_ANR_EVENT }).start(done); }); + + const EXPECTED_ISOLATED_EVENT = { + user: { + id: 5, + }, + exception: { + values: [ + { + type: 'ApplicationNotResponding', + value: 'Application Not Responding for at least 100 ms', + mechanism: { type: 'ANR' }, + stacktrace: { + frames: expect.arrayContaining([ + { + colno: expect.any(Number), + lineno: expect.any(Number), + filename: expect.stringMatching(/isolated.mjs$/), + function: 'longWork', + in_app: true, + }, + ]), + }, + }, + ], + }, + }; + + test('fetches correct isolated scope', done => { + createRunner(__dirname, 'isolated.mjs').expect({ event: EXPECTED_ISOLATED_EVENT }).start(done); + }); }); diff --git a/packages/node-experimental/src/integrations/anr/index.ts b/packages/node-experimental/src/integrations/anr/index.ts index c1bc03bc5a86..7dbe9e905cb4 100644 --- a/packages/node-experimental/src/integrations/anr/index.ts +++ b/packages/node-experimental/src/integrations/anr/index.ts @@ -1,8 +1,9 @@ -import { defineIntegration, getCurrentScope } from '@sentry/core'; -import type { Contexts, Event, EventHint, Integration, IntegrationFn } from '@sentry/types'; -import { logger } from '@sentry/utils'; +import { defineIntegration, mergeScopeData } from '@sentry/core'; +import type { Contexts, Event, EventHint, Integration, IntegrationFn, ScopeData } from '@sentry/types'; +import { GLOBAL_OBJ, logger } from '@sentry/utils'; import * as inspector from 'inspector'; import { Worker } from 'worker_threads'; +import { getCurrentScope, getGlobalScope, getIsolationScope } from '../..'; import { NODE_VERSION } from '../../nodeVersion'; import type { NodeClient } from '../../sdk/client'; import type { AnrIntegrationOptions, WorkerStartData } from './common'; @@ -15,8 +16,26 @@ function log(message: string, ...args: unknown[]): void { logger.log(`[ANR] ${message}`, ...args); } +function globalWithScopeFetchFn(): typeof GLOBAL_OBJ & { __SENTRY_GET_SCOPES__?: () => ScopeData } { + return GLOBAL_OBJ; +} + +/** Fetches merged scope data */ +function getScopeData(): ScopeData { + const scope = getGlobalScope().getScopeData(); + mergeScopeData(scope, getIsolationScope().getScopeData()); + mergeScopeData(scope, getCurrentScope().getScopeData()); + + // We remove attachments because they likely won't serialize well as json + scope.attachments = []; + // We can't serialize event processor functions + scope.eventProcessors = []; + + return scope; +} + /** - * Gets contexts by calling all event processors. This relies on being called after all integrations are setup + * Gets contexts by calling all event processors. This shouldn't be called until all integrations are setup */ async function getContexts(client: NodeClient): Promise { let event: Event | null = { message: 'ANR' }; @@ -35,9 +54,18 @@ const INTEGRATION_NAME = 'Anr'; type AnrInternal = { startWorker: () => void; stopWorker: () => void }; const _anrIntegration = ((options: Partial = {}) => { + if (NODE_VERSION.major < 16 || (NODE_VERSION.major === 16 && NODE_VERSION.minor < 17)) { + throw new Error('ANR detection requires Node 16.17.0 or later'); + } + let worker: Promise<() => void> | undefined; let client: NodeClient | undefined; + // Hookup the scope fetch function to the global object so that it can be called from the worker thread via the + // debugger when it pauses + const gbl = globalWithScopeFetchFn(); + gbl.__SENTRY_GET_SCOPES__ = getScopeData; + return { name: INTEGRATION_NAME, startWorker: () => { @@ -59,10 +87,6 @@ const _anrIntegration = ((options: Partial = {}) => { } }, setup(initClient: NodeClient) { - if (NODE_VERSION.major < 16 || (NODE_VERSION.major === 16 && NODE_VERSION.minor < 17)) { - throw new Error('ANR detection requires Node 16.17.0 or later'); - } - client = initClient; // setImmediate is used to ensure that all other integrations have had their setup called first. diff --git a/packages/node-experimental/src/integrations/anr/worker.ts b/packages/node-experimental/src/integrations/anr/worker.ts index 9f8147a280cf..21bdcbbb0631 100644 --- a/packages/node-experimental/src/integrations/anr/worker.ts +++ b/packages/node-experimental/src/integrations/anr/worker.ts @@ -1,11 +1,12 @@ import { + applyScopeDataToEvent, createEventEnvelope, createSessionEnvelope, getEnvelopeEndpointWithUrlEncodedAuth, makeSession, updateSession, } from '@sentry/core'; -import type { Event, Session, StackFrame, TraceContext } from '@sentry/types'; +import type { Event, ScopeData, Session, StackFrame } from '@sentry/types'; import { callFrameToStackFrame, normalizeUrlToBase, @@ -86,7 +87,23 @@ function prepareStackFrames(stackFrames: StackFrame[] | undefined): StackFrame[] return strippedFrames; } -async function sendAnrEvent(frames?: StackFrame[], traceContext?: TraceContext): Promise { +function applyScopeToEvent(event: Event, scope: ScopeData): void { + applyScopeDataToEvent(event, scope); + + if (!event.contexts?.trace) { + const { traceId, spanId, parentSpanId } = scope.propagationContext; + event.contexts = { + trace: { + trace_id: traceId, + span_id: spanId, + parent_span_id: parentSpanId, + }, + ...event.contexts, + }; + } +} + +async function sendAnrEvent(frames?: StackFrame[], scope?: ScopeData): Promise { if (hasSentAnrEvent) { return; } @@ -99,7 +116,7 @@ async function sendAnrEvent(frames?: StackFrame[], traceContext?: TraceContext): const event: Event = { event_id: uuid4(), - contexts: { ...options.contexts, trace: traceContext }, + contexts: options.contexts, release: options.release, environment: options.environment, dist: options.dist, @@ -119,6 +136,10 @@ async function sendAnrEvent(frames?: StackFrame[], traceContext?: TraceContext): tags: options.staticTags, }; + if (scope) { + applyScopeToEvent(event, scope); + } + const envelope = createEventEnvelope(event, options.dsn, options.sdkMetadata, options.tunnel); // Log the envelope to aid in testing log(JSON.stringify(envelope)); @@ -171,20 +192,23 @@ if (options.captureStackTrace) { 'Runtime.evaluate', { // Grab the trace context from the current scope - expression: - 'var __sentry_ctx = __SENTRY__.acs?.getCurrentScope().getPropagationContext() || {}; __sentry_ctx.traceId + "-" + __sentry_ctx.spanId + "-" + __sentry_ctx.parentSpanId', + expression: 'global.__SENTRY_GET_SCOPES__();', // Don't re-trigger the debugger if this causes an error silent: true, + // Serialize the result to json otherwise only primitives are supported + returnByValue: true, }, - (_, param) => { - const traceId = param && param.result ? (param.result.value as string) : '--'; - const [trace_id, span_id, parent_span_id] = traceId.split('-') as (string | undefined)[]; + (err, param) => { + if (err) { + log(`Error executing script: '${err.message}'`); + } + + const scopes = param && param.result ? (param.result.value as ScopeData) : undefined; session.post('Debugger.resume'); session.post('Debugger.disable'); - const context = trace_id?.length && span_id?.length ? { trace_id, span_id, parent_span_id } : undefined; - sendAnrEvent(stackFrames, context).then(null, () => { + sendAnrEvent(stackFrames, scopes).then(null, () => { log('Sending ANR event failed.'); }); }, From e05767477c627753c3191bd715d9ab1c368d4be4 Mon Sep 17 00:00:00 2001 From: Tim Fish Date: Mon, 25 Mar 2024 14:55:19 +0000 Subject: [PATCH 14/39] test(browser): Test webpack 5 + Terser (#11249) Tests that an app built with webpack 5 and minified with terser can be built and sends events at runtime --- .github/workflows/build.yml | 3 +- .../test-applications/webpack-5/.npmrc | 2 + .../test-applications/webpack-5/build.mjs | 44 ++++++++++++ .../test-applications/webpack-5/entry.js | 11 +++ .../test-applications/webpack-5/package.json | 18 +++++ .../webpack-5/playwright.config.ts | 70 +++++++++++++++++++ .../webpack-5/tests/behaviour-test.spec.ts | 44 ++++++++++++ 7 files changed, 191 insertions(+), 1 deletion(-) create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/.npmrc create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/build.mjs create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/entry.js create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/package.json create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/playwright.config.ts create mode 100644 dev-packages/e2e-tests/test-applications/webpack-5/tests/behaviour-test.spec.ts diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3d8562473837..b179159f4dfd 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1048,7 +1048,8 @@ jobs: # TODO(v8): Re-enable hapi tests # 'node-hapi-app', 'node-exports-test-app', - 'vue-3' + 'vue-3', + 'webpack-5' ] build-command: - false diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/.npmrc b/dev-packages/e2e-tests/test-applications/webpack-5/.npmrc new file mode 100644 index 000000000000..070f80f05092 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/.npmrc @@ -0,0 +1,2 @@ +@sentry:registry=http://127.0.0.1:4873 +@sentry-internal:registry=http://127.0.0.1:4873 diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/build.mjs b/dev-packages/e2e-tests/test-applications/webpack-5/build.mjs new file mode 100644 index 000000000000..11874cb62374 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/build.mjs @@ -0,0 +1,44 @@ +import * as path from 'path'; +import * as url from 'url'; +import HtmlWebpackPlugin from 'html-webpack-plugin'; +import TerserPlugin from 'terser-webpack-plugin'; +import webpack from 'webpack'; + +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + +webpack( + { + entry: path.join(__dirname, 'entry.js'), + output: { + path: path.join(__dirname, 'build'), + filename: 'app.js', + }, + optimization: { + minimize: true, + minimizer: [new TerserPlugin()], + }, + plugins: [new HtmlWebpackPlugin(), new webpack.EnvironmentPlugin(['E2E_TEST_DSN'])], + mode: 'production', + }, + (err, stats) => { + if (err) { + console.error(err.stack || err); + if (err.details) { + console.error(err.details); + } + return; + } + + const info = stats.toJson(); + + if (stats.hasErrors()) { + console.error(info.errors); + process.exit(1); + } + + if (stats.hasWarnings()) { + console.warn(info.warnings); + process.exit(1); + } + }, +); diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/entry.js b/dev-packages/e2e-tests/test-applications/webpack-5/entry.js new file mode 100644 index 000000000000..4fd9cd67e7e3 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/entry.js @@ -0,0 +1,11 @@ +import { browserTracingIntegration, captureException, init } from '@sentry/browser'; + +init({ + dsn: process.env.E2E_TEST_DSN, + integrations: [browserTracingIntegration()], +}); + +setTimeout(() => { + const eventId = captureException(new Error('I am an error!')); + window.capturedExceptionId = eventId; +}, 2000); diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/package.json b/dev-packages/e2e-tests/test-applications/webpack-5/package.json new file mode 100644 index 000000000000..871e43589971 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/package.json @@ -0,0 +1,18 @@ +{ + "name": "webpack-5-test", + "version": "1.0.0", + "scripts": { + "start": "serve -s build", + "build": "node build.mjs", + "test:build": "pnpm install && npx playwright install && pnpm build", + "test:assert": "playwright test" + }, + "devDependencies": { + "@playwright/test": "^1.42.1", + "@sentry/browser": "latest || *", + "webpack": "^5.91.0", + "terser-webpack-plugin": "^5.3.10", + "html-webpack-plugin": "^5.6.0", + "serve": "^14.2.1" + } +} diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/playwright.config.ts b/dev-packages/e2e-tests/test-applications/webpack-5/playwright.config.ts new file mode 100644 index 000000000000..5f93f826ebf0 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/playwright.config.ts @@ -0,0 +1,70 @@ +import type { PlaywrightTestConfig } from '@playwright/test'; +import { devices } from '@playwright/test'; + +/** + * See https://playwright.dev/docs/test-configuration. + */ +const config: PlaywrightTestConfig = { + testDir: './tests', + /* Maximum time one test can run for. */ + timeout: 150_000, + expect: { + /** + * Maximum time expect() should wait for the condition to be met. + * For example in `await expect(locator).toHaveText();` + */ + timeout: 5000, + }, + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: 0, + /* Opt out of parallel tests on CI. */ + workers: 1, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'list', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Maximum time each action such as `click()` can take. Defaults to 0 (no limit). */ + actionTimeout: 0, + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { + ...devices['Desktop Chrome'], + }, + }, + // For now we only test Chrome! + // { + // name: 'firefox', + // use: { + // ...devices['Desktop Firefox'], + // }, + // }, + // { + // name: 'webkit', + // use: { + // ...devices['Desktop Safari'], + // }, + // }, + ], + + /* Run your local dev server before starting the tests */ + webServer: { + command: 'pnpm start', + port: 3030, + env: { + PORT: '3030', + }, + }, +}; + +export default config; diff --git a/dev-packages/e2e-tests/test-applications/webpack-5/tests/behaviour-test.spec.ts b/dev-packages/e2e-tests/test-applications/webpack-5/tests/behaviour-test.spec.ts new file mode 100644 index 000000000000..4f762a4028d4 --- /dev/null +++ b/dev-packages/e2e-tests/test-applications/webpack-5/tests/behaviour-test.spec.ts @@ -0,0 +1,44 @@ +import { expect, test } from '@playwright/test'; +import axios, { AxiosError } from 'axios'; + +const EVENT_POLLING_TIMEOUT = 90_000; + +const authToken = process.env.E2E_TEST_AUTH_TOKEN; +const sentryTestOrgSlug = process.env.E2E_TEST_SENTRY_ORG_SLUG; +const sentryTestProject = process.env.E2E_TEST_SENTRY_TEST_PROJECT; + +test('Sends an exception to Sentry', async ({ page }) => { + await page.goto('/'); + + const exceptionIdHandle = await page.waitForFunction(() => window.capturedExceptionId); + const exceptionEventId = await exceptionIdHandle.jsonValue(); + + console.log(`Polling for error eventId: ${exceptionEventId}`); + + await expect + .poll( + async () => { + try { + const response = await axios.get( + `https://sentry.io/api/0/projects/${sentryTestOrgSlug}/${sentryTestProject}/events/${exceptionEventId}/`, + { headers: { Authorization: `Bearer ${authToken}` } }, + ); + return response.status; + } catch (e) { + if (e instanceof AxiosError && e.response) { + if (e.response.status !== 404) { + throw e; + } else { + return e.response.status; + } + } else { + throw e; + } + } + }, + { + timeout: EVENT_POLLING_TIMEOUT, + }, + ) + .toBe(200); +}); From 87eed515efaf5dc289566d72f14113d9474fb9d2 Mon Sep 17 00:00:00 2001 From: Onur Temizkan Date: Mon, 25 Mar 2024 15:11:43 +0000 Subject: [PATCH 15/39] fix(node): Skip capturing Hapi Boom error responses. (#11151) Resolves: https://github.com/getsentry/sentry-javascript/issues/11069 After checking the behaviour, it seems to me that we don't need to capture any Boom responses, as the errors that may cause a `5xx` response are already captured by the core logic. To add an option to control this behaviour, we need to update the usage of `hapiErrorPlugin`, converting it to a function signature, which IMO may not worth doing, as I'm not sure if users in general would need to use it. This also adds `expectError()` to the `node-integration-tests` runner to allow `5xx` responses to be tested. --- .../tracing-experimental/hapi/scenario.js | 25 +++++++++++++ .../suites/tracing-experimental/hapi/test.ts | 35 +++++++++++++++++++ .../node-integration-tests/utils/runner.ts | 18 +++++++++- packages/node/src/integrations/hapi/index.ts | 8 +---- 4 files changed, 78 insertions(+), 8 deletions(-) diff --git a/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/scenario.js b/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/scenario.js index 9a00fa36957d..69443559e9a8 100644 --- a/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/scenario.js +++ b/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/scenario.js @@ -9,6 +9,7 @@ Sentry.init({ }); const Hapi = require('@hapi/hapi'); +const Boom = require('@hapi/boom'); const port = 5999; @@ -26,6 +27,30 @@ const init = async () => { }, }); + server.route({ + method: 'GET', + path: '/error', + handler: (_request, _h) => { + return new Error('Sentry Test Error'); + }, + }); + + server.route({ + method: 'GET', + path: '/boom-error', + handler: (_request, _h) => { + return new Boom.Boom('Sentry Test Error'); + }, + }); + + server.route({ + method: 'GET', + path: '/promise-error', + handler: async (_request, _h) => { + return Promise.reject(new Error('Sentry Test Error')); + }, + }); + await Sentry.setupHapiErrorHandler(server); await server.start(); diff --git a/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/test.ts b/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/test.ts index 93e3203f6470..da8a07c20cc1 100644 --- a/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/test.ts +++ b/dev-packages/node-integration-tests/suites/tracing-experimental/hapi/test.ts @@ -25,10 +25,45 @@ describe('hapi auto-instrumentation', () => { ]), }; + const EXPECTED_ERROR_EVENT = { + exception: { + values: [ + { + type: 'Error', + value: 'Sentry Test Error', + }, + ], + }, + }; + test('CJS - should auto-instrument `@hapi/hapi` package.', done => { createRunner(__dirname, 'scenario.js') .expect({ transaction: EXPECTED_TRANSACTION }) .start(done) .makeRequest('get', '/'); }); + + test('CJS - should handle returned plain errors in routes.', done => { + createRunner(__dirname, 'scenario.js') + .expect({ event: EXPECTED_ERROR_EVENT }) + .expectError() + .start(done) + .makeRequest('get', '/error'); + }); + + test('CJS - should handle returned Boom errors in routes.', done => { + createRunner(__dirname, 'scenario.js') + .expect({ event: EXPECTED_ERROR_EVENT }) + .expectError() + .start(done) + .makeRequest('get', '/boom-error'); + }); + + test('CJS - should handle promise rejections in routes.', done => { + createRunner(__dirname, 'scenario.js') + .expect({ event: EXPECTED_ERROR_EVENT }) + .expectError() + .start(done) + .makeRequest('get', '/promise-error'); + }); }); diff --git a/dev-packages/node-integration-tests/utils/runner.ts b/dev-packages/node-integration-tests/utils/runner.ts index 515a2627acf8..5da33508bda0 100644 --- a/dev-packages/node-integration-tests/utils/runner.ts +++ b/dev-packages/node-integration-tests/utils/runner.ts @@ -126,6 +126,7 @@ export function createRunner(...paths: string[]) { let withSentryServer = false; let dockerOptions: DockerOptions | undefined; let ensureNoErrorOutput = false; + let expectError = false; if (testPath.endsWith('.ts')) { flags.push('-r', 'ts-node/register'); @@ -136,6 +137,10 @@ export function createRunner(...paths: string[]) { expectedEnvelopes.push(expected); return this; }, + expectError: function () { + expectError = true; + return this; + }, withFlags: function (...args: string[]) { flags.push(...args); return this; @@ -347,7 +352,18 @@ export function createRunner(...paths: string[]) { } const url = `http://localhost:${scenarioServerPort}${path}`; - if (method === 'get') { + if (expectError) { + try { + if (method === 'get') { + await axios.get(url, { headers }); + } else { + await axios.post(url, { headers }); + } + } catch (e) { + return; + } + return; + } else if (method === 'get') { return (await axios.get(url, { headers })).data; } else { return (await axios.post(url, { headers })).data; diff --git a/packages/node/src/integrations/hapi/index.ts b/packages/node/src/integrations/hapi/index.ts index 0c500fbd1ae1..58e329479f6a 100644 --- a/packages/node/src/integrations/hapi/index.ts +++ b/packages/node/src/integrations/hapi/index.ts @@ -23,10 +23,6 @@ function isResponseObject(response: ResponseObject | Boom): response is Response return response && (response as ResponseObject).statusCode !== undefined; } -function isBoomObject(response: ResponseObject | Boom): response is Boom { - return response && (response as Boom).isBoom !== undefined; -} - function isErrorEvent(event: RequestEvent): event is RequestEvent { return event && (event as RequestEvent).error !== undefined; } @@ -54,9 +50,7 @@ export const hapiErrorPlugin = { const activeSpan = getActiveSpan(); const rootSpan = activeSpan && getRootSpan(activeSpan); - if (request.response && isBoomObject(request.response)) { - sendErrorToSentry(request.response); - } else if (isErrorEvent(event)) { + if (isErrorEvent(event)) { sendErrorToSentry(event.error); } From 2090a0e89e2282dabfb18e047f28051c900aa088 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 25 Mar 2024 13:07:07 -0400 Subject: [PATCH 16/39] feat(v8/ember): Remove deprecated StartTransactionFunction (#11270) ref https://github.com/getsentry/sentry-javascript/issues/10100 --- MIGRATION.md | 2 +- packages/ember/addon/types.ts | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/MIGRATION.md b/MIGRATION.md index 23ba5c4b4c25..4e3c606da191 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -918,7 +918,7 @@ replacement API. ### Ember SDK -Removed top-level exports: `InitSentryForEmber` +Removed top-level exports: `InitSentryForEmber`, `StartTransactionFunction` - [Removal of `InitSentryForEmber` export](./MIGRATION.md#removal-of-initsentryforember-export) diff --git a/packages/ember/addon/types.ts b/packages/ember/addon/types.ts index 1b6825442be1..468cde6c310f 100644 --- a/packages/ember/addon/types.ts +++ b/packages/ember/addon/types.ts @@ -1,5 +1,4 @@ import type { BrowserOptions, browserTracingIntegration } from '@sentry/browser'; -import type { Transaction, TransactionContext } from '@sentry/types'; type BrowserTracingOptions = Parameters[0]; @@ -31,8 +30,6 @@ export interface EmberRouterMain { rootURL: string; }; } -/** @deprecated This will be removed in v8. */ -export type StartTransactionFunction = (context: TransactionContext) => Transaction | undefined; export type GlobalConfig = { __sentryEmberConfig: EmberSentryConfig['sentry']; From da83bbda49752a8b68600011d7744a713ad477e6 Mon Sep 17 00:00:00 2001 From: Abhijeet Prasad Date: Mon, 25 Mar 2024 13:15:59 -0400 Subject: [PATCH 17/39] feat(v8/core): Remove spanMetadata field (#11271) ref https://github.com/getsentry/sentry-javascript/issues/10100 --- packages/core/src/tracing/transaction.ts | 3 - .../core/test/lib/tracing/transaction.test.ts | 7 +- .../test/fixtures/transaction.ts | 106 ------------------ packages/types/src/transaction.ts | 6 - 4 files changed, 1 insertion(+), 121 deletions(-) diff --git a/packages/core/src/tracing/transaction.ts b/packages/core/src/tracing/transaction.ts index a95fe7c394f9..2469594ad687 100644 --- a/packages/core/src/tracing/transaction.ts +++ b/packages/core/src/tracing/transaction.ts @@ -97,9 +97,6 @@ export class Transaction extends SentrySpan implements TransactionInterface { public get metadata(): TransactionMetadata { // We merge attributes in for backwards compatibility return { - // Defaults - spanMetadata: {}, - // Legacy metadata ...this._metadata, diff --git a/packages/core/test/lib/tracing/transaction.test.ts b/packages/core/test/lib/tracing/transaction.test.ts index 781b9bdc1472..aebdc7933fed 100644 --- a/packages/core/test/lib/tracing/transaction.test.ts +++ b/packages/core/test/lib/tracing/transaction.test.ts @@ -32,15 +32,12 @@ describe('transaction', () => { /* eslint-disable deprecation/deprecation */ it('works with defaults', () => { const transaction = new Transaction({ name: 'span name' }); - expect(transaction.metadata).toEqual({ - spanMetadata: {}, - }); + expect(transaction.metadata).toEqual({}); }); it('allows to set metadata in constructor', () => { const transaction = new Transaction({ name: 'span name', metadata: { request: {} } }); expect(transaction.metadata).toEqual({ - spanMetadata: {}, request: {}, }); }); @@ -57,7 +54,6 @@ describe('transaction', () => { expect(transaction.metadata).toEqual({ sampleRate: 0.5, - spanMetadata: {}, request: {}, }); @@ -74,7 +70,6 @@ describe('transaction', () => { transaction.setMetadata({ request: {} }); expect(transaction.metadata).toEqual({ - spanMetadata: {}, request: {}, }); }); diff --git a/packages/replay-internal/test/fixtures/transaction.ts b/packages/replay-internal/test/fixtures/transaction.ts index a732c3c0dbb1..6264802f74d8 100644 --- a/packages/replay-internal/test/fixtures/transaction.ts +++ b/packages/replay-internal/test/fixtures/transaction.ts @@ -115,112 +115,6 @@ export function Transaction(traceId?: string, obj?: Partial): any { trace_id: '3e0ff8aff4dc4236a80b77a37ef66c7d', sample_rate: '1', }, - spanMetadata: { - '9ea106e8efbce4a0': { - logMessage: - "[Tracing] Starting 'ui.react.mount' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b4c7b421761d903a: { - logMessage: - "[Tracing] Starting 'ui.react.update' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '808967f15cae9251': { - logMessage: - "[Tracing] Starting 'ui.long-task' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '9a0de85dfd88085c': { - logMessage: - "[Tracing] Starting 'ui.react.render' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '863c6099f1929910': { - logMessage: - "[Tracing] Starting 'ui.react.update' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '87497c337838d561': { - logMessage: - "[Tracing] Starting 'http.client' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '81638bb5251f9e3f': { - logMessage: - "[Tracing] Starting 'http.client' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - bf25ff92b2dc7498: { - logMessage: - "[Tracing] Starting 'ui.long-task' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - a7c3320e88b04076: { - logMessage: - "[Tracing] Starting 'ui.react.update' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '95c892e987b8e0f5': { - logMessage: - "[Tracing] Starting 'ui.long-task' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b734c15c4d94b7b6: { - logMessage: - "[Tracing] Starting 'ui.long-task' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '934881bfe9a8e043': { - logMessage: - "[Tracing] Starting 'http.client' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '9bc8a019012e4692': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b3c5eb78c15aa492: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '84a72c34a78232b7': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b523103902ac1f0d: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '84f863de30175a64': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b0532b585ec47f05: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '9c3612dc22c5aea5': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '82b74a44ef06ae13': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b2d11e8d407329fd: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - '98146db11c338f31': { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - a05774f4b2885c47: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - a0c0d4f8ec6bfcd7: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - ab2e6ef0852bfc64: { - logMessage: - "[Tracing] Starting 'resource.script' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - b7fad2cd42783af4: { - logMessage: - "[Tracing] Starting 'resource.other' span on transaction '/organizations/:orgId/replays/:replaySlug/' (b44b173b1c74a782).", - }, - }, sampleRate: 1, }, // }}} transaction_info: { diff --git a/packages/types/src/transaction.ts b/packages/types/src/transaction.ts index 533401455488..d3db4afe0add 100644 --- a/packages/types/src/transaction.ts +++ b/packages/types/src/transaction.ts @@ -186,12 +186,6 @@ export interface TransactionMetadata { /** For transactions tracing server-side request handling, the path of the request being tracked. */ /** TODO: If we rm -rf `instrumentServer`, this can go, too */ requestPath?: string; - - /** - * Metadata for the transaction's spans, keyed by spanId. - * @deprecated This will be removed in v8. - */ - spanMetadata: { [spanId: string]: { [key: string]: unknown } }; } /** From fca5c03fc3d7c60a5ad9e10c40e97c0cf6f03203 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B6ren=20Wegener?= Date: Mon, 25 Mar 2024 18:31:38 +0100 Subject: [PATCH 18/39] feat(feedback): Make "required" text for input elements configurable (#11152) (#11153) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #11152 This introduces an option `isRequiredLabel`, and I planned to also add `errorMessageText`. However, this PR is branched off from a version that is a couple days old. Right now, @c298lee is currently working on getsentry/sentry#63749, which is causing major changes and the current version on master doesn't work yet. Therefore, I didn't yet implement `errorMessageText`. So consider this PR as a PoC, and either feel free to tag me when the screenshot changes are done – then I'll redo the changes based on the version that supports screenshots – or add the option on your own; however you prefer :slightly_smiling_face: One open question: Until now, there was only the error message: > There was a problem submitting feedback, please wait and try again. Now, depending on the status code, we have three error messages: > - 'Unable to send Feedback. This is because of network issues, or because you are using an ad-blocker.' > - 'Unable to send Feedback. Invalid response from server.' > - 'Unable to send Feedback' Do you have a suggestion how we could make the message configurable, without introducing too many and redundant settings? Maybe we should go back to only one message? I'm not sure if an end-user cares about whether it is a network issue or a server error. --------- Co-authored-by: Billy Vong --- packages/feedback/src/constants/index.ts | 1 + packages/feedback/src/core/integration.ts | 3 +++ packages/feedback/src/modal/components/Form.tsx | 16 +++++++++++----- packages/feedback/src/modal/createDialog.tsx | 1 + packages/feedback/src/types/config.ts | 5 +++++ 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/feedback/src/constants/index.ts b/packages/feedback/src/constants/index.ts index 9804fdedf431..218f2e678494 100644 --- a/packages/feedback/src/constants/index.ts +++ b/packages/feedback/src/constants/index.ts @@ -20,6 +20,7 @@ export const MESSAGE_LABEL = 'Description'; export const NAME_PLACEHOLDER = 'Your Name'; export const NAME_LABEL = 'Name'; export const SUCCESS_MESSAGE_TEXT = 'Thank you for your report!'; +export const IS_REQUIRED_TEXT = '(required)'; export const FEEDBACK_WIDGET_SOURCE = 'widget'; export const FEEDBACK_API_SOURCE = 'api'; diff --git a/packages/feedback/src/core/integration.ts b/packages/feedback/src/core/integration.ts index befc2cc03495..a37aec267730 100644 --- a/packages/feedback/src/core/integration.ts +++ b/packages/feedback/src/core/integration.ts @@ -9,6 +9,7 @@ import { EMAIL_LABEL, EMAIL_PLACEHOLDER, FORM_TITLE, + IS_REQUIRED_TEXT, MESSAGE_LABEL, MESSAGE_PLACEHOLDER, NAME_LABEL, @@ -76,6 +77,7 @@ export const _feedbackIntegration = (({ nameLabel = NAME_LABEL, namePlaceholder = NAME_PLACEHOLDER, successMessageText = SUCCESS_MESSAGE_TEXT, + isRequiredText = IS_REQUIRED_TEXT, // FeedbackCallbacks onFormOpen, @@ -116,6 +118,7 @@ export const _feedbackIntegration = (({ nameLabel, namePlaceholder, successMessageText, + isRequiredText, onFormClose, onFormOpen, diff --git a/packages/feedback/src/modal/components/Form.tsx b/packages/feedback/src/modal/components/Form.tsx index 0b2b1bb98fb1..960b4c3d9038 100644 --- a/packages/feedback/src/modal/components/Form.tsx +++ b/packages/feedback/src/modal/components/Form.tsx @@ -29,6 +29,7 @@ export interface Props | 'showEmail' | 'showName' | 'submitButtonLabel' + | 'isRequiredText' > { defaultEmail: string; defaultName: string; @@ -66,6 +67,7 @@ export function Form({ showEmail, showName, submitButtonLabel, + isRequiredText, screenshotInput, }: Props): VNode { // TODO: set a ref on the form, and whenever an input changes call proceessForm() and setError() @@ -145,7 +147,7 @@ export function Form({ {showName ? (