diff --git a/.craft.yml b/.craft.yml index 4a6534af681a..d69334cd3f94 100644 --- a/.craft.yml +++ b/.craft.yml @@ -129,20 +129,19 @@ targets: includeNames: /^sentry-internal-eslint-config-sdk-\d.*\.tgz$/ # AWS Lambda Layer target - # TODO(v9): Once stable, re-add this target to publish the AWS Lambda layer - # - name: aws-lambda-layer - # includeNames: /^sentry-node-serverless-\d+.\d+.\d+(-(beta|alpha|rc)\.\d+)?\.zip$/ - # layerName: SentryNodeServerlessSDKv9 - # compatibleRuntimes: - # - name: node - # versions: - # - nodejs10.x - # - nodejs12.x - # - nodejs14.x - # - nodejs16.x - # - nodejs18.x - # - nodejs20.x - # license: MIT + - name: aws-lambda-layer + includeNames: /^sentry-node-serverless-\d+.\d+.\d+(-(beta|alpha|rc)\.\d+)?\.zip$/ + layerName: SentryNodeServerlessSDKv9 + compatibleRuntimes: + - name: node + versions: + - nodejs10.x + - nodejs12.x + - nodejs14.x + - nodejs16.x + - nodejs18.x + - nodejs20.x + license: MIT # CDN Bundle Target - name: gcs diff --git a/CHANGELOG.md b/CHANGELOG.md index 92bbcdf58d03..a0116544b2de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,7 @@ > [!IMPORTANT] -> If you are upgrading to the `8.x` versions of the SDK from `7.x` or below, make sure you follow our +> If you are upgrading to the `9.x` versions of the SDK from `8.x` or below, make sure you follow our > [migration guide](https://docs.sentry.io/platforms/javascript/migration/) first. @@ -10,7 +10,171 @@ - "You miss 100 percent of the chances you don't take. — Wayne Gretzky" — Michael Scott -Work in this release was contributed by @tjhiggins, @chris-basebone, @GrizliK1988, @davidturissini, @nwalters512, @aloisklink, @arturovt, @benjick, @maximepvrt, @mstrokin, @kunal-511, @jahands, @jrandolf, @tannerlinsley, @Zen-cronic, @maxmaxme and @nathankleyn. Thank you for your contributions! +## 9.0.0 + +Version `9.0.0` marks a release of the Sentry JavaScript SDKs that contains breaking changes. +The goal of this release is to trim down on unused and potentially confusing APIs, prepare the SDKs for future framework versions to build deeper instrumentation, and remove old polyfills to reduce the packages' size. + +### How To Upgrade + +Please carefully read through the migration guide in the Sentry docs on how to upgrade from version 8 to version 9. +Make sure to select your specific platform/framework in the top left corner: https://docs.sentry.io/platforms/javascript/migration/v8-to-v9/ + +A comprehensive migration guide outlining all changes for all the frameworks can be found within the Sentry JavaScript SDK Repository: https://github.com/getsentry/sentry-javascript/blob/develop/MIGRATION.md + +### Breaking Changes + +- doc(deno)!: Make Deno v2 the minimum supported version (#15085) +- feat!: Bump typescript to `~5.0.0` (#14758) +- feat!: Drop `nitro-utils` package (#14998) +- feat!: Only collect ip addresses with `sendDefaultPii: true` (#15084) +- feat!: Remove `autoSessionTracking` option (#14802) +- feat!: Remove `enableTracing` (#15078) +- feat!: Remove `getCurrentHub()`, `Hub`, and `getCurrentHubShim()` (#15122) +- feat!: Remove `spanId` from propagation context (#14733) +- feat!: Remove deprecated and unused code (#15077) +- feat!: Remove metrics API from the JS SDK (#14745) +- feat!: Require Node `>=18` as minimum supported version (#14749) +- feat(astro)!: Respect user-specified source map setting (#14941) +- feat(browser)!: Remove `captureUserFeedback` method (#14820) +- feat(build)!: Drop pre-ES2020 polyfills (#14882) +- feat(core)!: Add `normalizedRequest` to `samplingContext` (#14902) +- feat(core)!: Always use session from isolation scope (#14860) +- feat(core)!: Pass root spans to `beforeSendSpan` and disallow returning `null` (#14831) +- feat(core)!: Remove `BAGGAGE_HEADER_NAME` export (#14785) +- feat(core)!: Remove `TransactionNamingScheme` type (#14865) +- feat(core)!: Remove `addOpenTelemetryInstrumentation` method (#14792) +- feat(core)!: Remove `arrayify` method (#14782) +- feat(core)!: Remove `debugIntegration` and `sessionTimingIntegration` (#14747) +- feat(core)!: Remove `flatten` method (#14784) +- feat(core)!: Remove `getDomElement` method (#14797) +- feat(core)!: Remove `makeFifoCache` method (#14786) +- feat(core)!: Remove `memoBuilder` export & `WeakSet` fallback (#14859) +- feat(core)!: Remove `transactionContext` from `samplingContext` (#14904) +- feat(core)!: Remove `urlEncode` method (#14783) +- feat(core)!: Remove deprecated `Request` type (#14858) +- feat(core)!: Remove deprecated request data methods (#14896) +- feat(core)!: Remove standalone `Client` interface & deprecate `BaseClient` (#14800) +- feat(core)!: Remove validSeverityLevels export (#14765) +- feat(core)!: Stop accepting `event` as argument for `recordDroppedEvent` (#14999) +- feat(core)!: Stop setting user in `requestDataIntegration` (#14898) +- feat(core)!: Type sdkProcessingMetadata more strictly (#14855) +- feat(core)!: Update `hasTracingEnabled` to consider empty trace config (#14857) +- feat(core)!: Update `requestDataIntegration` handling (#14806) +- feat(deno)!: Remove deno prepack (#14829) +- feat(ember)!: Officially drop support for ember `<=3.x` (#15032) +- feat(nestjs)!: Move `nestIntegration` into nest sdk and remove `setupNestErrorHandler` (#14751) +- feat(nestjs)!: Remove `@WithSentry` decorator (#14762) +- feat(nestjs)!: Remove `SentryService` (#14759) +- feat(nextjs)!: Don't rely on Next.js Build ID for release names (#14939) +- feat(nextjs)!: Remove `experimental_captureRequestError` (#14607) +- feat(nextjs)!: Respect user-provided source map generation settings (#14956) +- feat(node)!: Add support for Prisma v6 and drop v5 support (#15120) +- feat(node)!: Avoid http spans by default for custom OTEL setups (#14678) +- feat(node)!: Collect request sessions via HTTP instrumentation (#14658) +- feat(node)!: Remove `processThreadBreadcrumbIntegration` (#14666) +- feat(node)!: Remove fine grained `registerEsmLoaderHooks` (#15002) +- feat(opentelemetry)!: Exclusively pass root spans through sampling pipeline (#14951) +- feat(pinia)!: Include state of all stores in breadcrumb (#15312) +- feat(react)!: Raise minimum supported TanStack Router version to `1.63.0` (#15030) +- feat(react)!: Remove deprecated `getNumberOfUrlSegments` method (#14744) +- feat(react)!: Remove deprecated react router methods (#14743) +- feat(react)!: Update `ErrorBoundary` `componentStack` type (#14742) +- feat(remix)!: Drop support for Remix v1 (#14988) +- feat(remix)!: Remove `autoInstrumentRemix` option (#15074) +- feat(solidstart)!: Default to `--import` setup and add `autoInjectServerSentry` (#14862) +- feat(solidstart)!: No longer export `sentrySolidStartVite` (#15143) +- feat(solidstart)!: Respect user-provided source map setting (#14979) +- feat(svelte)!: Disable component update tracking by default (#15265) +- feat(sveltekit)!: Drop support for SvelteKit @1.x (#15037) +- feat(sveltekit)!: Remove `fetchProxyScriptNonce` option (#15123) +- feat(sveltekit)!: Respect user-provided source map generation settings (#14886) +- feat(utils)!: Remove `@sentry/utils` package (#14830) +- feat(vue)!: Remove configuring Vue tracing options anywhere else other than through the `vueIntegration`'s `tracingOptions` option (#14856) +- feat(vue/nuxt)!: No longer create `"update"` spans for component tracking by default (#14602) +- fix(node)!: Fix name of `vercelAIIntegration` to `VercelAI` (#15298) +- fix(vue)!: Remove `logError` from `vueIntegration` (#14958) +- ref!: Don't polyfill optional chaining and nullish coalescing (#14603) +- ref(core)!: Cleanup internal types, including `ReportDialogOptions` (#14861) +- ref(core)!: Mark exceptions from `captureConsoleIntegration` as `handled: true` by default (#14734) +- ref(core)!: Move `shutdownTimeout` option type from core to node (#15217) +- ref(core)!: Remove `Scope` type interface in favor of using `Scope` class (#14721) +- ref(core)!: Remove backwards compatible SentryCarrier type (#14697) + +### Other Changes + +- chore(browser): Export ipAddress helpers for use in other SDKs (#15079) +- deps(node): Bump `import-in-the-middle` to `1.12.0` (#14796) +- feat(aws): Rename AWS lambda layer name to `SentryNodeServerlessSDKv9` (#14927) +- feat(aws-serverless): Upgrade OTEL deps (#15091) +- feat(browser): Set `user.ip_address` explicitly to `{{auto}}` (#15008) +- feat(core): Add `inheritOrSampleWith` helper to `traceSampler` (#15277) +- feat(core): Emit client reports for unsampled root spans on span start (#14936) +- feat(core): Rename `hasTracingEnabled` to `hasSpansEnabled` (#15309) +- feat(core): Streamline `SpanJSON` type (#14693) +- feat(deno): Don't bundle `@sentry/deno` (#15014) +- feat(deno): Don't publish to `deno.land` (#15016) +- feat(deno): Stop inlining types from core (#14729) +- feat(deps): Bump @opentelemetry/instrumentation-amqplib from 0.45.0 to 0.46.0 (#14835) +- feat(deps): Bump @opentelemetry/instrumentation-aws-lambda from 0.49.0 to 0.50.0 (#14833) +- feat(deps): Bump @opentelemetry/instrumentation-express from 0.46.0 to 0.47.0 (#14834) +- feat(deps): Bump @opentelemetry/instrumentation-mysql2 from 0.44.0 to 0.45.0 (#14836) +- feat(deps): Bump @opentelemetry/propagation-utils from 0.30.14 to 0.30.15 (#14832) +- feat(deps): bump @opentelemetry/context-async-hooks from 1.29.0 to 1.30.0 (#14869) +- feat(deps): bump @opentelemetry/instrumentation-generic-pool from 0.42.0 to 0.43.0 (#14870) +- feat(deps): bump @opentelemetry/instrumentation-knex from 0.43.0 to 0.44.0 (#14872) +- feat(deps): bump @opentelemetry/instrumentation-mongodb from 0.50.0 to 0.51.0 (#14871) +- feat(deps): bump @opentelemetry/instrumentation-tedious from 0.17.0 to 0.18.0 (#14868) +- feat(deps): bump @sentry/cli from 2.39.1 to 2.41.1 (#15173) +- feat(flags): Add Statsig browser integration (#15319) +- feat(gatsby): Preserve user-provided source map settings (#15006) +- feat(nestjs): Remove `SentryTracingInterceptor`, `SentryGlobalGraphQLFilter`, `SentryGlobalGenericFilter` (#14761) +- feat(nextjs): Directly forward `sourcemaps.disable` to webpack plugin (#15109) +- feat(node): Add `processSessionIntegration` (#15081) +- feat(node): Add missing `vercelAIIntegration` export (#15318) +- feat(node): Capture exceptions from `worker_threads` (#15105) +- feat(nuxt): Add enabled to disable Sentry module (#15337) +- feat(nuxt): add `silent`, `errorHandler`, `release` to `SourceMapsOptions` (#15246) +- feat(profiling-node): Use `@sentry-internal/node-cpu-profiler` (#15208) +- feat(replay): Update fflate to 0.8.2 (#14867) +- feat(solidstart): Add `autoInjectServerSentry: 'experimental_dynamic-import` (#14863) +- feat(sveltekit): Only inject fetch proxy script for SvelteKit < 2.16.0 (#15126) +- feat(user feedback): Adds draw tool for UF screenshot annotations (#15062) +- feat(user feedback): Adds toolbar for cropping and annotating (#15282) +- feat: Avoid class fields all-together (#14887) +- feat: Only emit `__esModule` properties in CJS modules when there is a default export (#15018) +- feat: Pass `parentSampleRate` to `tracesSampler` (#15024) +- feat: Propagate and use a sampling random (#14989) +- fix(browser): Remove `browserPerformanceTimeOrigin` side-effects (#14025) +- fix(core): Ensure debugIds are applied to all exceptions in an event (#14881) +- fix(core): Fork scope if custom scope is passed to `startSpanManual` (#14901) +- fix(core): Fork scope if custom scope is passed to `startSpan` (#14900) +- fix(core): Only fall back to `sendDefaultPii` for IP collection in `requestDataIntegration` (#15125) +- fix(nextjs): Flush with `waitUntil` in `captureRequestError` (#15146) +- fix(nextjs): Use batched devserver symbolication endpoint (#15335) +- fix(node): Don't leak `__span` property into breadcrumbs (#14798) +- fix(node): Ensure `httpIntegration` propagates traces (#15233) +- fix(node): Fix sample rand propagation for negative sampling decisions (#15045) +- fix(node): Missing `release` from ANR sessions (#15138) +- fix(node): Set the correct fallback URL fields for outgoing https requests if they are not defined (#15316) +- fix(nuxt): Detect Azure Function runtime for flushing with timeout (#15288) +- fix(react): From location can be undefined in Tanstack Router Instrumentation (#15235) +- fix(react): Import default for hoistNonReactStatics (#15238) +- fix(react): Support lazy-loaded routes and components. (#15039) +- fix(solidstart): Do not copy release-injection map file (#15302) +- ref(browser): Improve active span handling for `browserTracingIntegration` (#14959) +- ref(browser): Improve setting of propagation scope for navigation spans (#15108) +- ref(browser): Skip browser extension warning in non-debug builds (#15310) +- ref(browser): Update `supportsHistory` check & history usage (#14696) +- ref(core): Ensure non-recording root spans have frozen DSC (#14964) +- ref(core): Log debug message when capturing error events (#14701) +- ref(core): Move log message about invalid sample rate (#15215) +- ref(node): Streamline check for adding performance integrations (#15021) +- ref(react): Adapt tanstack router type (#15241) +- ref(svelte): Remove SvelteKit detection (#15313) +- ref(sveltekit): Clean up sub-request check (#15251) + +Work in this release was contributed by @aloisklink, @arturovt, @aryanvdesh, @benjick, @chris-basebone, @davidturissini, @GrizliK1988, @jahands, @jrandolf, @kunal-511, @maximepvrt, @maxmaxme, @mstrokin, @nathankleyn, @nwalters512, @tannerlinsley, @tjhiggins, and @Zen-cronic. Thank you for your contributions! ## 9.0.0-alpha.2 @@ -36,6 +200,192 @@ This release does not yet entail a comprehensive changelog as version 9 is not y For this release's iteration of the migration guide, see the [Migration Guide as per `9.0.0-alpha.0`](https://github.com/getsentry/sentry-javascript/blob/6e4b593adcc4ce951afa8ae0cda0605ecd226cda/docs/migration/v8-to-v9.md). Please note that the migration guide is work in progress and subject to change. +## 8.54.0 + +- feat(v8/deps): Upgrade all OpenTelemetry dependencies ([#15098](https://github.com/getsentry/sentry-javascript/pull/15098)) +- fix(node/v8): Add compatibility layer for Prisma v5 ([#15210](https://github.com/getsentry/sentry-javascript/pull/15210)) + +Work in this release was contributed by @nwalters512. Thank you for your contribution! + +## 8.53.0 + +- feat(v8/nuxt): Add `url` to `SourcemapsUploadOptions` (#15202) +- fix(v8/react): `fromLocation` can be undefined in Tanstack Router Instrumentation (#15237) + +Work in this release was contributed by @tannerlinsley. Thank you for your contribution! + +## 8.52.1 + +- fix(v8/nextjs): Fix nextjs build warning (#15226) +- ref(v8/browser): Add protocol attributes to resource spans #15224 +- ref(v8/core): Don't set `this.name` to `new.target.prototype.constructor.name` (#15222) + +Work in this release was contributed by @Zen-cronic. Thank you for your contribution! + +## 8.52.0 + +### Important Changes + +- **feat(solidstart): Add `withSentry` wrapper for SolidStart config ([#15135](https://github.com/getsentry/sentry-javascript/pull/15135))** + +To enable the SolidStart SDK, wrap your SolidStart Config with `withSentry`. The `sentrySolidStartVite` plugin is now automatically +added by `withSentry` and you can pass the Sentry build-time options like this: + +```js +import { defineConfig } from '@solidjs/start/config'; +import { withSentry } from '@sentry/solidstart'; + +export default defineConfig( + withSentry( + { + /* Your SolidStart config options... */ + }, + { + // Options for setting up source maps + org: process.env.SENTRY_ORG, + project: process.env.SENTRY_PROJECT, + authToken: process.env.SENTRY_AUTH_TOKEN, + }, + ), +); +``` + +With the `withSentry` wrapper, the Sentry server config should not be added to the `public` directory anymore. +Add the Sentry server config in `src/instrument.server.ts`. Then, the server config will be placed inside the server build output as `instrument.server.mjs`. + +Now, there are two options to set up the SDK: + +1. **(recommended)** Provide an `--import` CLI flag to the start command like this (path depends on your server setup): + `node --import ./.output/server/instrument.server.mjs .output/server/index.mjs` +2. Add `autoInjectServerSentry: 'top-level-import'` and the Sentry config will be imported at the top of the server entry (comes with tracing limitations) + ```js + withSentry( + { + /* Your SolidStart config options... */ + }, + { + // Optional: Install Sentry with a top-level import + autoInjectServerSentry: 'top-level-import', + }, + ); + ``` + +### Other Changes + +- feat(v8/core): Add client outcomes for breadcrumbs buffer ([#15149](https://github.com/getsentry/sentry-javascript/pull/15149)) +- feat(v8/core): Improve error formatting in ZodErrors integration ([#15155](https://github.com/getsentry/sentry-javascript/pull/15155)) +- fix(v8/bun): Ensure instrumentation of `Bun.serve` survives a server reload ([#15157](https://github.com/getsentry/sentry-javascript/pull/15157)) +- fix(v8/core): Pass `module` into `loadModule` ([#15139](https://github.com/getsentry/sentry-javascript/pull/15139)) (#15166) + +Work in this release was contributed by @jahands, @jrandolf, and @nathankleyn. Thank you for your contributions! + +## 8.51.0 + +### Important Changes + +- **feat(v8/node): Add `prismaInstrumentation` option to Prisma integration as escape hatch for all Prisma versions ([#15128](https://github.com/getsentry/sentry-javascript/pull/15128))** + + This release adds a compatibility API to add support for Prisma version 6. + To capture performance data for Prisma version 6: + + 1. Install the `@prisma/instrumentation` package on version 6. + 1. Pass a `new PrismaInstrumentation()` instance as exported from `@prisma/instrumentation` to the `prismaInstrumentation` option: + + ```js + import { PrismaInstrumentation } from '@prisma/instrumentation'; + + Sentry.init({ + integrations: [ + prismaIntegration({ + // Override the default instrumentation that Sentry uses + prismaInstrumentation: new PrismaInstrumentation(), + }), + ], + }); + ``` + + The passed instrumentation instance will override the default instrumentation instance the integration would use, while the `prismaIntegration` will still ensure data compatibility for the various Prisma versions. + + 1. Remove the `previewFeatures = ["tracing"]` option from the client generator block of your Prisma schema. + +### Other Changes + +- feat(v8/browser): Add `multiplexedtransport.js` CDN bundle ([#15046](https://github.com/getsentry/sentry-javascript/pull/15046)) +- feat(v8/browser): Add Unleash integration ([#14948](https://github.com/getsentry/sentry-javascript/pull/14948)) +- feat(v8/deno): Deprecate Deno SDK as published on deno.land ([#15121](https://github.com/getsentry/sentry-javascript/pull/15121)) +- feat(v8/sveltekit): Deprecate `fetchProxyScriptNonce` option ([#15011](https://github.com/getsentry/sentry-javascript/pull/15011)) +- fix(v8/aws-lambda): Avoid overwriting root span name ([#15054](https://github.com/getsentry/sentry-javascript/pull/15054)) +- fix(v8/core): `fatal` events should set session as crashed ([#15073](https://github.com/getsentry/sentry-javascript/pull/15073)) +- fix(v8/node/nestjs): Use method on current fastify request ([#15104](https://github.com/getsentry/sentry-javascript/pull/15104)) + +Work in this release was contributed by @tjhiggins, and @nwalters512. Thank you for your contributions! + +## 8.50.0 + +- feat(v8/react): Add support for React Router `createMemoryRouter` ([#14985](https://github.com/getsentry/sentry-javascript/pull/14985)) + +## 8.49.0 + +- feat(v8/browser): Flush offline queue on flush and browser online event ([#14969](https://github.com/getsentry/sentry-javascript/pull/14969)) +- feat(v8/react): Add a `handled` prop to ErrorBoundary ([#14978](https://github.com/getsentry/sentry-javascript/pull/14978)) +- fix(profiling/v8): Don't put `require`, `__filename` and `__dirname` on global object ([#14952](https://github.com/getsentry/sentry-javascript/pull/14952)) +- fix(v8/node): Enforce that ContextLines integration does not leave open file handles ([#14997](https://github.com/getsentry/sentry-javascript/pull/14997)) +- fix(v8/replay): Disable mousemove sampling in rrweb for iOS browsers ([#14944](https://github.com/getsentry/sentry-javascript/pull/14944)) +- fix(v8/sveltekit): Ensure source maps deletion is called after source ma… ([#14963](https://github.com/getsentry/sentry-javascript/pull/14963)) +- fix(v8/vue): Re-throw error when no errorHandler exists ([#14943](https://github.com/getsentry/sentry-javascript/pull/14943)) + +Work in this release was contributed by @HHK1 and @mstrokin. Thank you for your contributions! + +## 8.48.0 + +### Deprecations + +- **feat(v8/core): Deprecate `getDomElement` method ([#14799](https://github.com/getsentry/sentry-javascript/pull/14799))** + + Deprecates `getDomElement`. There is no replacement. + +### Other changes + +- fix(nestjs/v8): Use correct main/module path in package.json ([#14791](https://github.com/getsentry/sentry-javascript/pull/14791)) +- fix(v8/core): Use consistent `continueTrace` implementation in core ([#14819](https://github.com/getsentry/sentry-javascript/pull/14819)) +- fix(v8/node): Correctly resolve debug IDs for ANR events with custom appRoot ([#14823](https://github.com/getsentry/sentry-javascript/pull/14823)) +- fix(v8/node): Ensure `NODE_OPTIONS` is not passed to worker threads ([#14825](https://github.com/getsentry/sentry-javascript/pull/14825)) +- fix(v8/angular): Fall back to element `tagName` when name is not provided to `TraceDirective` ([#14828](https://github.com/getsentry/sentry-javascript/pull/14828)) +- fix(aws-lambda): Remove version suffix from lambda layer ([#14843](https://github.com/getsentry/sentry-javascript/pull/14843)) +- fix(v8/node): Ensure express requests are properly handled ([#14851](https://github.com/getsentry/sentry-javascript/pull/14851)) +- feat(v8/node): Add `openTelemetrySpanProcessors` option ([#14853](https://github.com/getsentry/sentry-javascript/pull/14853)) +- fix(v8/react): Use `Set` as the `allRoutes` container. ([#14878](https://github.com/getsentry/sentry-javascript/pull/14878)) (#14884) +- fix(v8/react): Improve handling of routes nested under path="/" ([#14897](https://github.com/getsentry/sentry-javascript/pull/14897)) +- feat(v8/core): Add `normalizedRequest` to `samplingContext` ([#14903](https://github.com/getsentry/sentry-javascript/pull/14903)) +- fix(v8/feedback): Avoid lazy loading code for `syncFeedbackIntegration` ([#14918](https://github.com/getsentry/sentry-javascript/pull/14918)) + +Work in this release was contributed by @arturovt. Thank you for your contribution! + +## 8.47.0 + +- feat(v8/core): Add `updateSpanName` helper function (#14736) +- feat(v8/node): Do not overwrite prisma `db.system` in newer Prisma versions (#14772) +- feat(v8/node/deps): Bump @prisma/instrumentation from 5.19.1 to 5.22.0 (#14755) +- feat(v8/replay): Mask srcdoc iframe contents per default (#14779) +- ref(v8/nextjs): Fix typo in source maps deletion warning (#14776) + +Work in this release was contributed by @aloisklink and @benjick. Thank you for your contributions! + +## 8.46.0 + +- feat: Allow capture of more than 1 ANR event [v8] ([#14713](https://github.com/getsentry/sentry-javascript/pull/14713)) +- feat(node): Detect Railway release name [v8] ([#14714](https://github.com/getsentry/sentry-javascript/pull/14714)) +- fix: Normalise ANR debug image file paths if appRoot was supplied [v8] ([#14709](https://github.com/getsentry/sentry-javascript/pull/14709)) +- fix(nuxt): Remove build config from tsconfig ([#14737](https://github.com/getsentry/sentry-javascript/pull/14737)) + +Work in this release was contributed by @conor-ob. Thank you for your contribution! + +## 8.45.1 + +- fix(feedback): Return when the `sendFeedback` promise resolves ([#14683](https://github.com/getsentry/sentry-javascript/pull/14683)) + +Work in this release was contributed by @antonis. Thank you for your contribution! + ## 8.45.0 - feat(core): Add `handled` option to `captureConsoleIntegration` ([#14664](https://github.com/getsentry/sentry-javascript/pull/14664)) diff --git a/MIGRATION.md b/MIGRATION.md index e13e0d1148c0..cbd2a282db99 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -9,10 +9,10 @@ These docs walk through how to migrate our JavaScript SDKs through different maj # Upgrading from 8.x to 9.x -Version 9 of the Sentry JavaScript SDK concerns API cleanup and version support changes. -This update contains behavioral changes that will not be caught by type checkers, linters or tests, so we recommend carefully reading through the entire migration guide instead of purely relying on automatic tooling. +Version 9 of the Sentry JavaScript SDK primarily introduces API cleanup and version support changes. +This update contains behavioral changes that will not be caught by type checkers, linters, or tests, so we recommend carefully reading through the entire migration guide instead of relying on automatic tooling. -`v9` of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v8). +Version 9 of the SDK is compatible with Sentry self-hosted versions 24.4.2 or higher (unchanged from v8). Lower versions may continue to work, but may not support all features. ## 1. Version Support Changes: @@ -27,16 +27,16 @@ This includes features like Nullish Coalescing (`??`), Optional Chaining (`?.`), If you observe failures due to syntax or features listed above, it may indicate that your current runtime does not support ES2020. If your runtime does not support ES2020, we recommend transpiling the SDK using Babel or similar tooling. -**Node.js:** The minimum supported Node.js version is **18.0.0**, except for ESM-only SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/sveltekit`) which require Node.js version **18.19.1** or higher. +**Node.js:** The minimum supported Node.js version is **18.0.0** (Released Apr 19, 2022), except for ESM-only SDKs (`@sentry/astro`, `@sentry/nuxt`, `@sentry/sveltekit`) which require Node.js version **18.19.1** (Released Feb 14, 2024) or higher. **Browsers:** Due to SDK code now including ES2020 features, the minimum supported browser list now looks as follows: -- Chrome 80 -- Edge 80 -- Safari 14, iOS Safari 14.4 -- Firefox 74 -- Opera 67 -- Samsung Internet 13.0 +- Chrome 80 (Released Feb 5, 2020) +- Edge 80 (Released Feb 7, 2020) +- Safari 14, iOS Safari 14.4 (Released Sep 16, 2020) +- Firefox 74 (Released Mar 10, 2020) +- Opera 67 (Released Mar 12, 2020) +- Samsung Internet 13.0 (Released Nov 20, 2020) If you need to support older browsers, we recommend transpiling your code using SWC, Babel or similar tooling. @@ -54,11 +54,21 @@ Support for the following frameworks and library versions are dropped: ### TypeScript Version Policy -In preparation for v2 of the OpenTelemetry SDK, which will raise the minimum required TypeScript version, the minimum required TypeScript version is increased to version `5.0.4`. +In preparation for v2 of the OpenTelemetry SDK, the minimum required TypeScript version is increased to version `5.0.4`. Additionally, like the OpenTelemetry SDK, the Sentry JavaScript SDK will follow [DefinitelyType's version support policy](https://github.com/DefinitelyTyped/DefinitelyTyped#support-window) which has a support time frame of 2 years for any released version of TypeScript. -Older Typescript versions _may_ continue to be compatible, but no guarantees apply. +Older TypeScript versions _may_ continue to be compatible, but no guarantees apply. + +### AWS Lambda Layer Changes + +A new AWS Lambda Layer for version 9 will be published as `SentryNodeServerlessSDKv9`. +The ARN will be published in the [Sentry docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/install/cjs-layer/) once available. + +The previous `SentryNodeServerlessSDK` layer will not receive new updates anymore. + +Updates and fixes for version 8 will be published as `SentryNodeServerlessSDKv8`. +The ARN will be published in the [Sentry docs](https://docs.sentry.io/platforms/javascript/guides/aws-lambda/install/cjs-layer/) once available. ## 2. Behavior Changes @@ -80,7 +90,7 @@ Older Typescript versions _may_ continue to be compatible, but no guarantees app While in v8, the passed scope was set active directly on the passed scope, in v9, the scope is cloned. This behavior change does not apply to `@sentry/node` where the scope was already cloned. This change was made to ensure that the span only remains active within the callback and to align behavior between `@sentry/node` and all other SDKs. As a result of the change, span hierarchy should be more accurate. - However, modifying the scope (e.g. set tags) within the `startSpan` callback behaves a bit differently now. + However, modifying the scope (for example, setting tags) within the `startSpan` callback behaves a bit differently now. ```js startSpan({ name: 'example', scope: customScope }, () => { @@ -91,12 +101,12 @@ Older Typescript versions _may_ continue to be compatible, but no guarantees app ``` - Passing `undefined` as a `tracesSampleRate` option value will now be treated the same as if the attribute was not defined at all. - In previous versions, it was checked whether the `tracesSampleRate` property existed in the SDK options to determine whether to propagate trace data for distributed tracing. + In previous versions, it was checked whether the `tracesSampleRate` property existed in the SDK options to decide if trace data should be propagated for tracing. Consequentially, this sometimes caused the SDK to propagate negative sampling decisions when `tracesSampleRate: undefined` was passed. This is no longer the case and sampling decisions will be deferred to downstream SDKs for distributed tracing. This is more of a bugfix rather than a breaking change, however, depending on the setup of your SDKs, an increase in sampled traces may be observed. -- If you use the optional `captureConsoleIntegration` and set `attachStackTrace: true` in your `Sentry.init` call, console messages will no longer be marked as unhandled (i.e. `handled: false`) but as handled (i.e. `handled: true`). +- If you use the optional `captureConsoleIntegration` and set `attachStackTrace: true` in your `Sentry.init` call, console messages will no longer be marked as unhandled (`handled: false`) but as handled (`handled: true`). If you want to keep sending them as unhandled, configure the `handled` option when adding the integration: ```js diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/constants.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/constants.ts new file mode 100644 index 000000000000..680105d242e5 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/constants.ts @@ -0,0 +1 @@ +export const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/basic/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/basic/test.ts index ed909b19d1fa..5cf63a4914ed 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/basic/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/featureFlags/basic/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures'; import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; -const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. +import { FLAG_BUFFER_SIZE } from '../../constants'; sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => { if (shouldSkipFeatureFlagsTest()) { diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/basic/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/basic/test.ts index e97cb70761ba..d0adafc3d101 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/basic/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/launchdarkly/basic/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures'; import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; -const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. +import { FLAG_BUFFER_SIZE } from '../../constants'; sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => { if (shouldSkipFeatureFlagsTest()) { diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/basic/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/basic/test.ts index a3de589677ea..21db2c0b7d85 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/basic/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/basic/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures'; import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; -const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. +import { FLAG_BUFFER_SIZE } from '../../constants'; sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => { if (shouldSkipFeatureFlagsTest()) { diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/errorHook/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/errorHook/test.ts index 719782d0b0ab..bae111a5e6f5 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/errorHook/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/openfeature/errorHook/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures'; import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; -const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. +import { FLAG_BUFFER_SIZE } from '../../constants'; sentryTest('Flag evaluation error hook', async ({ getLocalTestUrl, page }) => { if (shouldSkipFeatureFlagsTest()) { diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/basic/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/basic/test.ts new file mode 100644 index 000000000000..5b484b91ba22 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/basic/test.ts @@ -0,0 +1,51 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../../utils/fixtures'; + +import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; + +import { FLAG_BUFFER_SIZE } from '../../constants'; + +sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => { + if (shouldSkipFeatureFlagsTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); + await page.goto(url); + + await page.evaluate(bufferSize => { + const client = (window as any).statsigClient; + for (let i = 1; i <= bufferSize; i++) { + client.checkGate(`feat${i}`); // values default to false + } + + client.setMockGateValue(`feat${bufferSize + 1}`, true); + client.checkGate(`feat${bufferSize + 1}`); // eviction + + client.setMockGateValue('feat3', true); + client.checkGate('feat3'); // update + }, FLAG_BUFFER_SIZE); + + const reqPromise = waitForErrorRequest(page); + await page.locator('#error').click(); + const req = await reqPromise; + const event = envelopeRequestParser(req); + + const expectedFlags = [{ flag: 'feat2', result: false }]; + for (let i = 4; i <= FLAG_BUFFER_SIZE; i++) { + expectedFlags.push({ flag: `feat${i}`, result: false }); + } + expectedFlags.push({ flag: `feat${FLAG_BUFFER_SIZE + 1}`, result: true }); + expectedFlags.push({ flag: 'feat3', result: true }); + + expect(event.contexts?.flags?.values).toEqual(expectedFlags); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/init.js b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/init.js new file mode 100644 index 000000000000..61d00587f4c6 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/init.js @@ -0,0 +1,35 @@ +import * as Sentry from '@sentry/browser'; + +class MockStatsigClient { + constructor() { + this._gateEvaluationListeners = []; + this._mockGateValues = {}; + } + + on(event, listener) { + this._gateEvaluationListeners.push(listener); + } + + checkGate(name) { + const value = this._mockGateValues[name] || false; // unknown features default to false. + this._gateEvaluationListeners.forEach(listener => { + listener({ gate: { name, value } }); + }); + return value; + } + + setMockGateValue(name, value) { + this._mockGateValues[name] = value; + } +} + +window.statsigClient = new MockStatsigClient(); + +window.Sentry = Sentry; +window.sentryStatsigIntegration = Sentry.statsigIntegration({ featureFlagClient: window.statsigClient }); + +Sentry.init({ + dsn: 'https://public@dsn.ingest.sentry.io/1337', + sampleRate: 1.0, + integrations: [window.sentryStatsigIntegration], +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/subject.js b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/subject.js new file mode 100644 index 000000000000..e6697408128c --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/subject.js @@ -0,0 +1,3 @@ +document.getElementById('error').addEventListener('click', () => { + throw new Error('Button triggered error'); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/template.html b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/template.html new file mode 100644 index 000000000000..9330c6c679f4 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/template.html @@ -0,0 +1,9 @@ + + +
+ + + + + + diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/withScope/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/withScope/test.ts new file mode 100644 index 000000000000..cf41767036b6 --- /dev/null +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/statsig/withScope/test.ts @@ -0,0 +1,69 @@ +import { expect } from '@playwright/test'; + +import { sentryTest } from '../../../../../utils/fixtures'; + +import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; + +import type { Scope } from '@sentry/browser'; + +sentryTest('Flag evaluations in forked scopes are stored separately.', async ({ getLocalTestUrl, page }) => { + if (shouldSkipFeatureFlagsTest()) { + sentryTest.skip(); + } + + await page.route('https://dsn.ingest.sentry.io/**/*', route => { + return route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ id: 'test-id' }), + }); + }); + + const url = await getLocalTestUrl({ testDir: __dirname, skipDsnRouteHandler: true }); + await page.goto(url); + + const forkedReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === true); + const mainReqPromise = waitForErrorRequest(page, event => !!event.tags?.isForked === false); + + await page.evaluate(() => { + const Sentry = (window as any).Sentry; + const errorButton = document.querySelector('#error') as HTMLButtonElement; + const client = (window as any).statsigClient; + + client.setMockGateValue('shared', true); + client.setMockGateValue('main', true); + + client.checkGate('shared'); + + Sentry.withScope((scope: Scope) => { + client.setMockGateValue('forked', true); + client.setMockGateValue('shared', false); // override the value in the parent scope. + + client.checkGate('forked'); + client.checkGate('shared'); + scope.setTag('isForked', true); + errorButton.click(); + }); + + client.checkGate('main'); + Sentry.getCurrentScope().setTag('isForked', false); + errorButton.click(); + return true; + }); + + const forkedReq = await forkedReqPromise; + const forkedEvent = envelopeRequestParser(forkedReq); + + const mainReq = await mainReqPromise; + const mainEvent = envelopeRequestParser(mainReq); + + expect(forkedEvent.contexts?.flags?.values).toEqual([ + { flag: 'forked', result: true }, + { flag: 'shared', result: false }, + ]); + + expect(mainEvent.contexts?.flags?.values).toEqual([ + { flag: 'shared', result: true }, + { flag: 'main', result: true }, + ]); +}); diff --git a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/unleash/basic/test.ts b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/unleash/basic/test.ts index 5bb72caddd24..7e8065dc6172 100644 --- a/dev-packages/browser-integration-tests/suites/integrations/featureFlags/unleash/basic/test.ts +++ b/dev-packages/browser-integration-tests/suites/integrations/featureFlags/unleash/basic/test.ts @@ -4,7 +4,7 @@ import { sentryTest } from '../../../../../utils/fixtures'; import { envelopeRequestParser, shouldSkipFeatureFlagsTest, waitForErrorRequest } from '../../../../../utils/helpers'; -const FLAG_BUFFER_SIZE = 100; // Corresponds to constant in featureFlags.ts, in browser utils. +import { FLAG_BUFFER_SIZE } from '../../constants'; sentryTest('Basic test with eviction, update, and no async tasks', async ({ getLocalTestUrl, page }) => { if (shouldSkipFeatureFlagsTest()) { diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/subject.js b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/subject.js index a51740976b6a..db9f6cb4616a 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/subject.js +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/subject.js @@ -1,6 +1,6 @@ window.calls = {}; const xhr = new XMLHttpRequest(); -xhr.open('GET', 'http://example.com'); +xhr.open('GET', 'http://sentry-test-site.example'); xhr.onreadystatechange = function wat() { window.calls[xhr.readyState] = window.calls[xhr.readyState] ? window.calls[xhr.readyState] + 1 : 1; }; diff --git a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/test.ts b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/test.ts index f9b1816c6f2d..5b693af2f9d4 100644 --- a/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/test.ts +++ b/dev-packages/browser-integration-tests/suites/public-api/instrumentation/xhr/onreadystatechange/test.ts @@ -7,7 +7,7 @@ sentryTest( async ({ getLocalTestUrl, page }) => { const url = await getLocalTestUrl({ testDir: __dirname }); - await page.route('http://example.com/', route => { + await page.route('http://sentry-test-site.example/', route => { return route.fulfill({ status: 200, contentType: 'application/json', diff --git a/dev-packages/browser-integration-tests/suites/replay/requests/subject.js b/dev-packages/browser-integration-tests/suites/replay/requests/subject.js index a58f304fc687..e3e775227709 100644 --- a/dev-packages/browser-integration-tests/suites/replay/requests/subject.js +++ b/dev-packages/browser-integration-tests/suites/replay/requests/subject.js @@ -6,11 +6,11 @@ document.getElementById('go-background').addEventListener('click', () => { }); document.getElementById('fetch').addEventListener('click', () => { - fetch('https://example.com', { method: 'POST', body: 'foo' }); + fetch('https://sentry-test-site.example', { method: 'POST', body: 'foo' }); }); document.getElementById('xhr').addEventListener('click', () => { const xhr = new XMLHttpRequest(); - xhr.open('GET', 'https://example.com'); + xhr.open('GET', 'https://sentry-test-site.example'); xhr.send(); }); diff --git a/dev-packages/browser-integration-tests/suites/replay/requests/test.ts b/dev-packages/browser-integration-tests/suites/replay/requests/test.ts index efb344382b69..fc7693bf1003 100644 --- a/dev-packages/browser-integration-tests/suites/replay/requests/test.ts +++ b/dev-packages/browser-integration-tests/suites/replay/requests/test.ts @@ -10,7 +10,7 @@ sentryTest('replay recording should contain fetch request span', async ({ getLoc sentryTest.skip(); } - await page.route('https://example.com', route => { + await page.route('https://sentry-test-site.example', route => { return route.fulfill({ status: 200, contentType: 'application/json', @@ -27,7 +27,7 @@ sentryTest('replay recording should contain fetch request span', async ({ getLoc const { performanceSpans: spans0 } = getReplayRecordingContent(req0); - await Promise.all([page.waitForResponse('https://example.com'), page.locator('#fetch').click()]); + await Promise.all([page.waitForResponse('https://sentry-test-site.example'), page.locator('#fetch').click()]); const { performanceSpans: spans1 } = getReplayRecordingContent(await reqPromise1); @@ -40,7 +40,7 @@ sentryTest('replay recording should contain XHR request span', async ({ getLocal sentryTest.skip(); } - await page.route('https://example.com', route => { + await page.route('https://sentry-test-site.example', route => { return route.fulfill({ status: 200, contentType: 'application/json', @@ -57,7 +57,7 @@ sentryTest('replay recording should contain XHR request span', async ({ getLocal const { performanceSpans: spans0 } = getReplayRecordingContent(req0); - await Promise.all([page.waitForResponse('https://example.com'), page.locator('#xhr').click()]); + await Promise.all([page.waitForResponse('https://sentry-test-site.example'), page.locator('#xhr').click()]); const { performanceSpans: spans1 } = getReplayRecordingContent(await reqPromise1); diff --git a/dev-packages/browser-integration-tests/suites/replay/slowClick/template.html b/dev-packages/browser-integration-tests/suites/replay/slowClick/template.html index a3f5d9d54882..d83848c1b70d 100644 --- a/dev-packages/browser-integration-tests/suites/replay/slowClick/template.html +++ b/dev-packages/browser-integration-tests/suites/replay/slowClick/template.html @@ -76,7 +76,7 @@