Skip to content

ref(feedback): Remove deprecated SentryFeedbackWidget - #3844

Merged
buenaflor merged 1 commit into
v10-branchfrom
ref/remove-sentry-feedback-widget
Jul 6, 2026
Merged

buenaflor merged 1 commit into
v10-branchfrom
ref/remove-sentry-feedback-widget

Conversation

@buenaflor

Copy link
Copy Markdown
Contributor

SentryFeedbackWidget is removed. It was a deprecated typedef alias (typedef SentryFeedbackWidget = SentryFeedbackForm) left over from the rename to SentryFeedbackForm, which is complete.

Removes the alias file, its export from sentry_flutter.dart, and the alias-specific test group. No other code referenced it.

Part of the v10 cleanup (#3487).

Breaking change: low impact — already deprecated with a documented migration to SentryFeedbackForm.

Fixes #3825

SentryFeedbackWidget was a deprecated typedef alias for
SentryFeedbackForm; the rename is complete, so remove the alias, its
export, and the alias-specific test group.

BREAKING CHANGE: SentryFeedbackWidget is removed; use SentryFeedbackForm.

Fixes GH-3825
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@github-actions

github-actions Bot commented Jul 1, 2026 •

Copy link
Copy Markdown
Contributor

Semver Impact of This PR

⚪ None (no version bump detected)

📋 Changelog Preview

This is how your changes will appear in the changelog.
Entries from this PR are highlighted with a left border (blockquote style).


Features

  • (grpc) Add integration support for GRPC by lucas-zimerman in #3721

Fixes

  • Correct feature flag scope buffer updates by denrase in #3797

Dependencies

Deps

  • chore(deps): update Android SDK to v8.46.0 by github-actions in #3793
  • chore(deps): update Native SDK to v0.15.2 by github-actions in #3785

Internal Changes

  • (feedback) Remove deprecated SentryFeedbackWidget by buenaflor in #3844
  • (skills) Expand test-guidelines and drop stale deps by buenaflor in #3807
  • Add PR template checkbox for cross sdk review on public API changes by antonis in #3822
  • Block manual CHANGELOG.md edits by buenaflor in #3810
  • Fix Dependabot pub paths and pin GitHub Action by buenaflor in #3804
  • Add AI Use section to CONTRIBUTING.md by christophaigner in #3803

🤖 This preview updates automatically when you update the PR.

@codecov

codecov Bot commented Jul 1, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
⚠️ Please upload report for BASE (v10-branch@59d7c7b). Learn more about missing BASE report.
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@              Coverage Diff              @@
##             v10-branch    #3844   +/-   ##
=============================================
  Coverage              ?   91.71%           
=============================================
  Files                 ?      105           
  Lines                 ?     3816           
  Branches              ?        0           
=============================================
  Hits                  ?     3500           
  Misses                ?      316           
  Partials              ?        0           
Flag Coverage Δ
sentry_firebase_remote_config 100.00% <ø> (?)
sentry_flutter 91.33% <ø> (?)
sentry_supabase 97.27% <ø> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

@buenaflor buenaflor changed the title ref(feedback)!: Remove deprecated SentryFeedbackWidget ref(feedback): Remove deprecated SentryFeedbackWidget Jul 1, 2026
@buenaflor
buenaflor marked this pull request as ready for review July 1, 2026 15:09
@buenaflor
buenaflor requested a review from denrase as a code owner July 1, 2026 15:09
Copilot AI review requested due to automatic review settings July 1, 2026 15:09

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Removes the deprecated SentryFeedbackWidget typedef alias (renamed to SentryFeedbackForm previously) from the Flutter package, including its now-obsolete export and alias-only tests, as part of the v10 cleanup.

Changes:

  • Deleted SentryFeedbackWidget alias file (sentry_feedback_widget.dart).
  • Removed the deprecated export from packages/flutter/lib/sentry_flutter.dart.
  • Removed the alias-specific test group from sentry_feedback_form_test.dart.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.

File Description
packages/flutter/test/feedback/sentry_feedback_form_test.dart Removes tests that only validated the deprecated alias behavior.
packages/flutter/lib/src/feedback/sentry_feedback_widget.dart Deletes the deprecated typedef alias (public API removal).
packages/flutter/lib/sentry_flutter.dart Stops exporting the removed alias symbol from the Flutter barrel.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@buenaflor
buenaflor merged commit e751495 into v10-branch Jul 6, 2026
63 of 64 checks passed
@buenaflor
buenaflor deleted the ref/remove-sentry-feedback-widget branch July 6, 2026 09:47
buenaflor added a commit that referenced this pull request Oct 12, 2026
* deps(flutter): Bump sentry-cocoa to 9.17.1 in v10 (#3764)

* feat(flutter)!: Bump sentry-cocoa to 9.17.1

Bump the embedded sentry-cocoa SDK from 8.58.3 to the latest 9.x.

Raise the minimum deployment targets to iOS 15 and macOS 12, as required
by sentry-cocoa 9. Migrate native code to the cocoa 9 API surface:

- Drop the removed `enableSessionReplayInUnreliableEnvironment` option
- Drop the removed `PrivateSentrySDKOnly.options.integrations` accessor
- Replace `PrivateSentrySDKOnly.getDebugImages()` with
  `debugImageProvider.getDebugImagesFromCache()`
- Format image addresses in Swift instead of the removed
  `sentry_formatHexAddressUInt64`
- Drop the obsolete `Sentry._Hybrid` submodule imports
- Build replay events via `SentrySRDefaultBreadcrumbConverter`,
  `SentryRRWebBreadcrumbEvent`, and `SentryRRWebSpanEvent`

Regenerate the FFI binding: PrivateSentrySDKOnly.h moved into Headers/ and
SentryId is now generated as a full interface, so the SentryId1/sed
workaround is removed.

Add scripts/build-macos-example.sh (and a melos build:macos-example alias)
to build the macOS example, working around Flutter deriving the SwiftPM
package identity from the plugin directory basename.

BREAKING CHANGE: minimum supported versions are now iOS 15 and macOS 12.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Depend on Sentry pod and fix cocoa 9 tests

sentry-cocoa 9 removed the Sentry/HybridSDK CocoaPods subspec; the hybrid
public headers now ship with the default Core subspec. Depend on `Sentry`
instead so pod resolution and pod-lint succeed, and update update-cocoa.sh to
match.

Bump the min_version_test iOS deployment target to 15 (cocoa 9's floor).

Update the loadContexts integration test: cocoa 9 exposes no accessor for
installed integration names, so native integrations are no longer reported.
Assert their absence and leave a TODO to restore once cocoa adds the accessor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Silence swiftlint todo rule on cocoa integrations note

The swift-lint CI job runs with --strict, which promotes the default todo
rule to an error. Keep the tracked TODO about restoring native integration
reporting and suppress just that line with swiftlint:disable:next todo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter): Harden macos build script and bump microbenchmarks targets

Add preflight checks to build-macos-example.sh so it refuses to run when
packages/sentry_flutter already exists (the rename would otherwise nest the
directory and the restore trap would corrupt the tree) or when
packages/flutter is missing. Install the EXIT trap only after the rename
succeeds.

Bump the microbenchmarks iOS and macOS deployment targets to 15.0 / 12.0 to
match the cocoa 9 minimums now required by the sentry_flutter podspec, keeping
them consistent with the example app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci(flutter): Update cocoa dep pattern to 9.x for v10

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* deps(flutter): Bump jni to 1.0.0 and jnigen to 0.16.0 in v10 (#3765)

* feat(flutter)!: Bump sentry-cocoa to 9.17.1

Bump the embedded sentry-cocoa SDK from 8.58.3 to the latest 9.x.

Raise the minimum deployment targets to iOS 15 and macOS 12, as required
by sentry-cocoa 9. Migrate native code to the cocoa 9 API surface:

- Drop the removed `enableSessionReplayInUnreliableEnvironment` option
- Drop the removed `PrivateSentrySDKOnly.options.integrations` accessor
- Replace `PrivateSentrySDKOnly.getDebugImages()` with
  `debugImageProvider.getDebugImagesFromCache()`
- Format image addresses in Swift instead of the removed
  `sentry_formatHexAddressUInt64`
- Drop the obsolete `Sentry._Hybrid` submodule imports
- Build replay events via `SentrySRDefaultBreadcrumbConverter`,
  `SentryRRWebBreadcrumbEvent`, and `SentryRRWebSpanEvent`

Regenerate the FFI binding: PrivateSentrySDKOnly.h moved into Headers/ and
SentryId is now generated as a full interface, so the SentryId1/sed
workaround is removed.

Add scripts/build-macos-example.sh (and a melos build:macos-example alias)
to build the macOS example, working around Flutter deriving the SwiftPM
package identity from the plugin directory basename.

BREAKING CHANGE: minimum supported versions are now iOS 15 and macOS 12.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Depend on Sentry pod and fix cocoa 9 tests

sentry-cocoa 9 removed the Sentry/HybridSDK CocoaPods subspec; the hybrid
public headers now ship with the default Core subspec. Depend on `Sentry`
instead so pod resolution and pod-lint succeed, and update update-cocoa.sh to
match.

Bump the min_version_test iOS deployment target to 15 (cocoa 9's floor).

Update the loadContexts integration test: cocoa 9 exposes no accessor for
installed integration names, so native integrations are no longer reported.
Assert their absence and leave a TODO to restore once cocoa adds the accessor.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Silence swiftlint todo rule on cocoa integrations note

The swift-lint CI job runs with --strict, which promotes the default todo
rule to an error. Keep the tracked TODO about restoring native integration
reporting and suppress just that line with swiftlint:disable:next todo.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter): Harden macos build script and bump microbenchmarks targets

Add preflight checks to build-macos-example.sh so it refuses to run when
packages/sentry_flutter already exists (the rename would otherwise nest the
directory and the restore trap would corrupt the tree) or when
packages/flutter is missing. Install the EXIT trap only after the rename
succeeds.

Bump the microbenchmarks iOS and macOS deployment targets to 15.0 / 12.0 to
match the cocoa 9 minimums now required by the sentry_flutter podspec, keeping
them consistent with the example app.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter)!: Bump jni to 1.0.0 and jnigen to 0.16.0

Move the Android JNI bindings to jni 1.0.0 / jnigen 0.16.0 (exact-pinned,
since jni 1.0.0 adds a compile-time consistency check between the runtime and
the committed generated binding).

- Regenerate binding.dart via a new programmatic generator (tool/jnigen.dart)
  that replaces ffi-jni.yaml. A visitor excludes four unused setters whose
  @Nullable getter / non-null setter pair JNIgen 1.0.0 emits as invalid Dart.
- Migrate the hand-written interop and integration tests to the 1.0.0 API:
  getX()/setX() to getters/setters, JList.array/JMap.hash to JArrayList/
  JHashMap, JByteArray.from to allocate-then-fill, intValue/longValue/etc. to
  toDartInt/toDartDouble/toDartBool, and collection access via asDart().
- Update the regeneration scripts to call the new generator.

BREAKING CHANGE: jni is now pinned to 1.0.0 (was 0.14.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Address Copilot review on jni bump

- safe-regenerate-jni.sh: the fallback path still called the removed
  ffi-jni.yaml; point it at tool/jnigen.dart like the normal path.
- integration_test.dart: use toDartDouble(releaseOriginal: true) for the
  sample-rate assertion, consistent with the rest of the migrated test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter)!: Raise min Flutter to 3.35.6 for jni 1.0.0

jni 1.0.0 requires Flutter >=3.35.6 (Dart 3.9.2), so the min_version_test
job failed version solving against the old 3.24.0 floor. Raise the minimum
supported Flutter/Dart in the flutter package, the min_version_test app, the
min-version CI workflow, and the agent docs to match.

BREAKING CHANGE: minimum supported Flutter is now 3.35.6 (Dart 3.9.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter): Drop manual changelog entry

Per CONTRIBUTING.md, changelog entries are auto-generated by craft from the
PR title; no manual CHANGELOG.md edits are needed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(flutter): Extract shared JNI byte-array helpers

The toJByteArray and jsonToJByteArray helpers were duplicated across
sentry_native_java.dart and android_core_worker.dart. Move them into a
single jni_byte_array.dart so both files share one implementation.

No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* fix(flutter): Repoint integration test to relocated helper

jsonToJByteArray moved to jni_byte_array.dart during the helper
consolidation, but the JNI integration test still imported it from
sentry_native_java.dart, breaking the kernel snapshot build. Import it
from the new location.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Apply dart format from Flutter stable

CI runs dart format with the current Flutter stable (3.44.x), whose
dart_style reformats files committed under an older version. Reformat
the package so 'dart format --set-exit-if-changed' passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* build(flutter): Update min_version_test Android for Flutter 3.35.6

The min version bump to Flutter 3.35.6 left the min_version_test Android
project on the legacy imperative plugin setup, which newer Flutter no
longer supports. Migrate to the declarative Gradle plugins block and
raise the toolchain to Flutter 3.35.6's minimums:

- settings.gradle: declarative pluginManagement + plugins block
- build.gradle: drop the buildscript block (plugins resolved above)
- app/build.gradle: apply plugins via the plugins block
- Gradle wrapper 8.2 -> 8.4 (filePermissions API needs >= 8.3)
- Kotlin 1.8.0 -> 1.8.10 (Flutter's minimum supported version)

Verified with 'flutter build appbundle' on Flutter 3.35.6.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Format binding.dart with Dart 3.12 dart_style

CI's Flutter stable bundles Dart 3.12, whose dart_style joins the
') implements' clause of extension types onto one line. The earlier
reformat used Dart 3.10 locally, which left this file one change short.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Resolve analyzer lints under flutter_lints 6

The SDK/Flutter bump pulls flutter_lints 6.0.0 (analyzer 13), which
enables new lints and fails the strict 'dart analyze' gate:

- use_null_aware_elements: rewrite 'if (x != null) k: x' map entries to
  the null-aware 'k: ?x' form (dart fix)
- unnecessary_underscores: collapse '__'/'___' params to '_' (dart fix)
- invalid_use_of_internal_member: the reformat moved line-level
  '// ignore:' comments off their target lines; replace with file-level
  '// ignore_for_file:' in sentry_script_loader.dart and the feature
  flag integration test

Verified: dart analyze clean, dart format gate passes, and
min_version_test still builds on Flutter 3.35.6 (Dart 3.9.2).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(flutter): Support SwiftPM on Flutter 3.44+ (#3784)

* feat(flutter): Support SwiftPM on Flutter 3.44+

Flutter 3.44 exposes its framework as an explicit FlutterFramework
SwiftPM package. Plugins must declare a dependency on it; otherwise the
build emits a deprecation warning that becomes a hard error in a future
Flutter release.

Add FlutterFramework to both the Swift and ObjC SwiftPM targets (both
import Flutter/FlutterMacOS). Raise the minimum Flutter to 3.44.0 (Dart
3.12.0) since FlutterFramework is unavailable on older versions, and
update min_version_test to match.

Verified by building the iOS and macOS example apps with SwiftPM
enabled (warning gone) and with CocoaPods.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: Run pana directly to support Flutter 3.44+

The axel-op/dart-package-analyzer action is unmaintained and its
bundled Flutter SDK is frozen at 3.38.6, so it cannot resolve packages
that require a newer Flutter. After raising sentry_flutter to Flutter
3.44, package-analysis failed with a version-solving error.

Replace the action with an explicit SDK setup (setup-dart or
flutter-action) plus a direct `pana --json` run, reading the score from
.scores.grantedPoints/.maxPoints. Verified locally that packages/dart
(160/160) and packages/flutter (150/160) clear the 140 threshold.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci: Modernize min_version_test Android build for 3.44

Flutter 3.44's Gradle plugin requires Gradle >=8.7.0, so the min
version test app failed to build with its pinned Gradle 8.4. Bump Gradle
to 8.9, AGP to 8.6.0, and Kotlin to 2.0.21 to match the example app, and
keep the Flutter migrator's android.newDsl/builtInKotlin opt-outs.

Verified by building the appbundle locally on Flutter 3.44.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Satisfy prefer_initializing_formals lint

Flutter stable advanced to 3.44.3, whose analyzer enforces
prefer_initializing_formals and fails the 'dart analyze' gate. Convert
the flagged constructors to initializing formals, and exclude the
generated lib/src/native/java/binding.dart from analysis (consistent
with the already-excluded cocoa/binding.dart).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci(flutter): Fix min_version_test Android OOM on Flutter 3.44

After bumping min_version_test to Flutter 3.44.0, the release build
OOMs (Java heap space) during the Jetifier transform of the larger
Flutter embedding jar. Disable Jetifier (not needed for AndroidX) and
raise the Gradle heap to 4G.

Verified with 'flutter build appbundle' on Flutter 3.44.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Format native files with Dart 3.12

These files came from main during the v10-branch sync and carried
main's formatting; CI formats with stable Flutter's bundled Dart (3.12),
which reformats them, so dart format --set-exit-if-changed failed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* style(flutter): Remove doubled word in native log message

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* release: 10.0.0-alpha.1

* ref(feedback)!: Remove deprecated SentryFeedbackWidget (#3844)

SentryFeedbackWidget was a deprecated typedef alias for
SentryFeedbackForm; the rename is complete, so remove the alias, its
export, and the alias-specific test group.

BREAKING CHANGE: SentryFeedbackWidget is removed; use SentryFeedbackForm.

Fixes GH-3825

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(logs): Remove deprecated SentryLogAttribute (#3843)

SentryLogAttribute was already @Deprecated and merely duplicated
SentryAttribute's scalar factories while lacking its array variants.
Nothing in the SDK referenced it anymore, so remove it and leave
SentryAttribute as the single attribute type.

BREAKING CHANGE: SentryLogAttribute is removed; use SentryAttribute.

Fixes GH-3826

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(logs): Enable logs by default (#3846)

Flip SentryOptions.enableLogs default from false to true so logs work
out of the box, matching enableMetrics. Logs are only sent when the
user emits them - by calling Sentry.logger.* or by explicitly adding a
log-emitting integration (LoggingIntegration is the only one and is
never auto-registered), so the flip alone sends nothing.

Document the opt-in contract on enableLogs and LoggingIntegration, pin
the new default with a test, and opt metrics-focused lifecycle tests
out of logs explicitly.

Fixes GH-3682
Fixes GH-3833

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

* ref!: Remove deprecated performance collectors (#3850)

Remove the deprecated PerformanceCollector /
PerformanceContinuousCollector API and the
options.performanceCollectors / addPerformanceCollector() surface.

These predate the SdkLifecycleHooks model, which now covers the same
span start/finish hooks via OnSpanStart / OnSpanFinish. The SDK's own
frame tracking already runs entirely on the lifecycle registry, so the
collector loops in the tracer and span-finish paths were redundant with
the adjacent lifecycle dispatch. Both static and stream trace lifecycles
remain fully served by the lifecycle hooks.

BREAKING CHANGE: PerformanceCollector, PerformanceContinuousCollector,
SentryOptions.performanceCollectors and addPerformanceCollector() are
removed. The lifecycle-hook replacement is internal; there is no public
replacement API.

Fixes #3831

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(logs): Make logger methods return void (#3852)

* ref(dart)!: Make logger methods return void

SentryLogger and SentryLoggerFormatter methods (trace/debug/info/warn/
error/fatal) were declared FutureOr<void> but are always fire-and-forget in
practice — the internal capture pipeline already handles errors internally,
so nothing awaits the result. Narrow them to void.

DefaultSentryLogger now fires its capture callback via unawaited(),
mirroring DefaultSentryMetrics. The internal capture chain (Hub.captureLog,
SentryClient.captureLog, HubAdapter.captureLog, LogCapturePipeline.captureLog,
and the Noop variants) narrows from FutureOr<void> to Future<void> for
consistency with the equivalent metrics pipeline; these are already async,
so this is a type-precision fix with no behavior change.

sentry_logging's LoggingIntegration no longer awaits the now-void logger
calls.

BREAKING CHANGE: SentryLogger and SentryLoggerFormatter methods now return
void instead of FutureOr<void>.

Fixes GH-3851
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(firebase_remote_config): Narrow mocked Hub.captureLog signature

The generated MockHub still declared captureLog as FutureOr<void>,
which no longer satisfies Hub.captureLog's Future<void> signature and
broke compilation on all platforms.

Refs GH-3851
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>

* fix(firebase_remote_config): Add mock return values for captureLog

The hand-edited mock cast noSuchMethod's result to a non-nullable
Future<void> without providing returnValue or returnValueForMissingStub,
so stubbing or calling captureLog on MockHub would throw a TypeError at
runtime. Add both defaults, matching mockito's generated output for
Future<void> methods and the equivalent mocks in packages/flutter.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 5 <noreply@anthropic.com>

* chore(grpc): Bump version to 10.0.0-alpha.1

sentry_grpc was skipped by the 10.0.0-alpha.1 release bump and drifted
to 9.23.0 via the main merge. Align the package version, sentry
dependency pin, and reported sdkVersion with the other v10 packages.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* feat(logs): Add Hint to beforeSend for logs, metrics, and spans (#3847)

* feat(logs): Add Hint to beforeSend for logs, metrics, spans

beforeSendLog, beforeSendMetric, and beforeSendSpan now receive a Hint
as their second argument, matching beforeSend and beforeSendTransaction.

Each capture pipeline creates one Hint and threads that same instance
through the OnProcessLog/Metric/Span lifecycle event and into the
callback, so SDK-side lifecycle callbacks can enrich the hint before
beforeSend reads it. Public capture APIs are unchanged.

Also migrate the metric pipeline's callback-error log from the
deprecated options.log to internalLogger.

BREAKING CHANGE: user-defined beforeSendLog/beforeSendMetric/
beforeSendSpan callbacks must add the Hint parameter.

Fixes GH-3836
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* ref(file): Remove file.async attributes from instrumentation (#3841)

* ref(file)!: Remove file.async attributes from instrumentation

The file.async span attribute and breadcrumb data was a
Sentry-invented signal with no product feature consuming it — a dead
signal on every file-I/O span and breadcrumb. Remove it from both the
async and sync paths. The sync attribute is left untouched.

BREAKING CHANGE: Consumers relying on file.async for filtering or
sampling lose the signal.

Fixes GH-3830
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(file): Fix typo in breadcrumb assert helper name

Rename _asserBreadcrumb to _assertBreadcrumb for consistency with
the other assert helpers in the file.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(dart): Make feature flags hub/scope-based (#3848)

* ref(dart)!: Make feature flags hub/scope-based

Move the feature-flag buffer logic off FeatureFlagsIntegration and onto
Scope/Hub, mirroring the addBreadcrumb path. Sentry.addFeatureFlag now
delegates through the hub instead of reaching into options.integrations.

FeatureFlagsIntegration is deleted, so events no longer report
"FeatureFlagsIntegration" in sdk.integrations. Usage is now tracked via
the "featureFlags" entry in sdk.features, recorded on actual use.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(dart): Read feature flags context field directly

Avoid copying the whole contexts map via the public getter on each
addFeatureFlag call; read the internal _contexts field instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(flutter): Pass Hint to OnProcessSpan in thread info tests

v10-branch #3847 added a Hint parameter to OnProcessSpan while the
thread info tests from #3821 landed in parallel still using the
single-argument constructor, breaking compilation on the base branch.
Pass an empty Hint like the other call sites.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref: Make clone() internal and remove deprecated protocol clones (#3845)

* ref!: Make clone() internal; drop protocol clones

clone() on Hub, Scope, NoOpHub, HubAdapter and Sentry is intended
for SDK-internal use only, so mark it @internal.

The protocol clone() methods (Contexts and its children) were already
@Deprecated and formed a dead subtree with no remaining callers, so
remove them along with the alias-only clone context test.

BREAKING CHANGE: The deprecated clone() on protocol classes is removed,
and clone() on Hub/Scope is now @internal.

Fixes GH-3824
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref: Rename feature flag copy() to clone()

Align internal naming with Hub.clone() and Scope.clone(). The copy
name existed only to avoid clashing with the deprecated public clone()
API, which this branch removes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(flutter): Fix OnProcessSpan calls missing Hint

PR #3847 added a required hint parameter to OnProcessSpan but missed
the five call sites in thread_info_integration_test.dart, which landed
in parallel. This breaks compilation of the flutter test suite and the
analyze gate on v10-branch, failing CI for every PR based on it.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* chore(metrics): Raise Android binary size budget

The v10 feature work pushed the with-Sentry APK size diff to ~1409 KiB,
past the 1350 KiB budget, failing the SDK metrics job on v10-branch and
every PR based on it. Raise diffMax to 1450 KiB, following the same
pattern as #3324 and #3567.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(logs): Make traceId required on SentryLog (#3842)

SentryLog.traceId was nullable and defaulted to SentryId.empty(),
so a log could be constructed without a real trace association and
was only patched later in the capture pipeline.

Make traceId a required, non-nullable constructor parameter and drop
the SentryId.empty() fallback. The pipeline no longer needs to
populate traceId from the scope, so that compensating block is
removed; the scope attribute merge is unchanged.

BREAKING CHANGE: Constructing SentryLog without a traceId no longer
compiles.

Fixes GH-3835

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* release: 10.0.0-alpha.2

* chore: Complete 10.0.0-alpha.2 changelog entries (#3861)

* chore: Complete 10.0.0-alpha.2 changelog entries

Add the PRs merged since alpha.1 that were missing from the
10.0.0-alpha.2 section, categorized to match the existing format.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: Drop alpha.2 entries already in 9.23.0

#3784, #3765, and #3764 were released in 9.23.0 and were
duplicated in the 10.0.0-alpha.2 section. Removing them empties
the Dependencies section, so drop that too.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* Update CHANGELOG for version 10.0.0-alpha.1

Add new features, enhancements, and dependency updates for version 10.0.0-alpha.1.

* feat(telemetry): Align span attributes with Sentry Conventions (#3805)

* feat(telemetry)!: Align span attributes with Sentry Conventions

Cross-check every attribute in the core constants against the Sentry
Conventions source of truth and align the SDK with the stable names.

- Remove deprecated, unused attribute constants whose stable replacement
  was already in use (app.app_*, os.build, device.connection_type) and
  drop the inaccurate "deprecated" comments on device.locale /
  device.timezone, which are not deprecated in the conventions.
- Hard-rename db.system to db.system.name across all database
  integrations (drift, hive, isar, sqflite, supabase).
- Remove the SentrySpanData key bag in favor of SemanticAttributesConstants
  for codified attributes and ProposedSemanticAttributes for keys that are
  not (yet) part of the conventions (db.schema, db.url, db.sdk, db.body).
- Supabase now emits db.operation.name, db.query.text and
  db.collection.name instead of db.operation, db.query and db.table.
- Move app.vitals.start.value to ProposedSemanticAttributes since it is
  not a codified convention.
- Keep each integration's db.system.name value as a named constant in
  production, but assert the literal value in tests so the assertions are
  not tautological. Correct drift's value from db.sqlite to the standard
  sqlite.

BREAKING CHANGE: database span attribute keys changed to match Sentry
Conventions (db.system.name, db.operation.name, db.query.text,
db.collection.name).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(integrations): Use SemanticAttributesConstants for db keys

Drop the per-integration dbSystemKey / dbNameKey constants in hive, isar
and sqflite and reference SemanticAttributesConstants.dbSystemName /
.dbName directly, since those keys are now defined canonically there.
The integration-specific db.system value constant (dbSystem) stays local,
and tests assert the literal attribute keys.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(integrations)!: Emit db.namespace instead of db.name

Rename SemanticAttributesConstants.dbName to dbNamespace ('db.namespace')
and emit it across all database integrations (drift, hive, isar, sqflite),
aligning with the OTel/Sentry convention where db.namespace supersedes the
legacy db.name.

BREAKING CHANGE: database spans now carry db.namespace instead of db.name.
db.name has no Relay backfill (deprecation _status is null), so this is a
hard cutover for consumers querying that attribute.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(telemetry)!: Align DB, HTTP and app start span attributes

Continue aligning emitted span attributes with Sentry Conventions.

Supabase DB spans now carry the SQL statement on the convention key
db.query.text (with ? placeholders, so it is value-free and emitted
regardless of sendDefaultPii) plus a low-cardinality db.query.summary,
replacing the raw PostgREST filter list and the misuse of the operation
name db.sql.query as a data key. generateSqlQuery() now builds the
projection and WHERE clause for SELECT so the statement is complete.

Isar now emits db.collection.name instead of the custom db.collection.

HTTP spans now emit url.full instead of the bare url key and
http.response.body.size instead of the deprecated
http.response_content_length (Relay backfills the latter).

The Flutter app start handler emits app.vitals.start.type instead of the
custom app_start_type, matching the span-v2 handler.

Production code now references SemanticAttributesConstants for these keys
instead of string literals.

BREAKING CHANGE: db.query.text now holds the SQL statement, db.collection
(Isar), bare url and app_start_type are no longer emitted. db.collection.name,
url.full and app.vitals.start.type have no Relay backfill.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat: Add sentry.trace_lifecycle span attribute (#3811)

Mark spans with how they were sent so the product can distinguish
streamed from transaction-sent spans (per sentry-conventions#442).

- stream mode: set "stream" on each streamed span in the capture
  pipeline (user/beforeSendSpan values still win).
- static mode: set "static" on the transaction trace context and on
  each child span at creation time.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

* ref(telemetry): Rename db-system value constants to dbSystemName

The emitted key is db.system.name, so rename the per-integration value
constants (postgresql, sqlite, flutter_hive, isar) from the dbSystem
prefix to dbSystemName to match. Pure rename; the emitted values are
unchanged.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ref(telemetry): Use constants for file.path and file.size attributes

Add file.path and file.size to ProposedSemanticAttributes (they have no
Sentry Conventions home yet) and reference them from the file and asset
bundle integrations instead of string literals. No wire change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* ref(supabase): Move db.query.text and summary work to a follow-up PR

Revert the Supabase query-attribute changes from this PR so they can be
reviewed separately: db.query.text now goes back to the raw PostgREST
filter list, the generated SQL returns to the db.sql.query key, and the
db.query.summary attribute and generateSqlQuery() SELECT completion are
removed (along with the unused dbQuerySummary constant).

The foundational key migration (db.operation.name, db.collection.name,
db.system.name, db.schema/url/sdk/body) stays in this PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(supabase): Keep raw query filters on db.query not db.query.text

The db.query.text convention expects value-free parameterized SQL, but
the raw PostgREST filter list (value-inlined and PII-gated) was being
written there. Park the filter list on the legacy, non-convention
db.query key instead; the proper db.query.text SQL payload lands in the
follow-up PR.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* feat(supabase): Emit SQL in db.query.text and add db.query.summary (#3817)

* feat(supabase)!: Emit SQL in db.query.text and add db.query.summary

Introduce db.query.text holding the parameterized SQL statement (with ?
placeholders, value-free, emitted regardless of sendDefaultPii) and
migrate the raw PostgREST filter list off the legacy db.query key.
generateSqlQuery() now builds the projection and WHERE clause for SELECT
so the statement is complete, a low-cardinality db.query.summary is
added, and the misuse of the db.sql.query operation name as a data key
is removed.

Stacked on the telemetry-alignment PR, which keeps the raw filters on the
legacy db.query key.

BREAKING CHANGE: the raw filter list under db.query is replaced by the SQL
statement under db.query.text; the value under db.sql.query is gone.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(supabase): Represent not() filter as NOT in db.query.text

generateSqlQuery() rendered PostgREST .not(column, op, value) filters as
`column = ?` because _getOperatorSql had no `not` case and fell through to
`=`. Negated filters now render as `NOT (column <op> ?)`.

This pre-existing flaw affected UPDATE/DELETE on v10 and became visible
for SELECT once the WHERE clause was added.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(supabase): Exclude pagination params from WHERE

PostgREST sorting/pagination params (order, limit, offset) were
translated as pseudo-filters and leaked into the SELECT WHERE clause
of db.query.text, e.g. `.select().order('id')` produced
`SELECT * FROM "t" WHERE order = ?`.

Skip these reserved params in _buildWhereClause so they no longer
appear as bogus column predicates.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>

* fix(supabase): Map is filter to IS and unify NOT rendering

The is filter (e.g. .is_('deleted', null)) fell through _getOperatorSql
to the default '=', rendering db.query.text as "deleted = ?" instead of
"deleted IS ?". Add the missing case.

The pre-existing filter(not, ...) path rendered "column != ?" while the
new not(column, op, value) path renders "NOT (column = ?)", so the same
NOT concept appeared two ways. Render both as "NOT (column = ?)".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ref(supabase): Read select projection from the query param

_buildSelectColumns reconstructed the projection by scanning the
translated query list for a select(...) entry and stripping it with a
magic substring(7, ...). Read request.url.queryParameters['select']
directly instead, dropping the round-trip, the magic offset, and the
first-match-only loop. No behavior change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* feat(flutter): Make native request capture opt-in (#3885)

* feat(flutter)!: Make native request capture opt-in

Default native failed-request capture to false and remove its fallback to
the Dart-side capture option. This keeps Cocoa HTTP errors opt-in.

BREAKING CHANGE: captureNativeFailedRequests is now a non-nullable bool
and defaults to false. Set it to true to keep native iOS/macOS
failed-request capture enabled.

Fixes GH-3834
Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test(flutter): Clarify native capture independence

Rename bridge tests around the native option's independent contract.
Remove duplicate default coverage.

Refs GH-3834
Co-Authored-By: OpenAI Codex <noreply@openai.com>

* test(dart): Follow local options test style

Keep the new default assertion flat like the surrounding legacy tests
instead of introducing a one-off group.

Refs GH-3834
Co-Authored-By: OpenAI Codex <noreply@openai.com>

---------

Co-authored-by: OpenAI Codex <noreply@openai.com>

* style(flutter): Format delayed frames test

Apply the Flutter SDK's bundled Dart formatter to keep the package aligned with CI formatting.

Co-Authored-By: Codex <noreply@openai.com>

* ref(dart): Remove deprecated copyWith methods (#3877)

* ref!: Remove deprecated copyWith methods

Remove protocol copyWith APIs as part of the v10 cleanup.

SentryRuntime.copyWith was intended to be deprecated as well.

Callers should assign mutable fields or reconstruct immutable values.

BREAKING CHANGE: Protocol copyWith methods are no longer available.
Fixes GH-3823
Co-Authored-By: Codex <noreply@openai.com>

* ref!: Remove SentryEventLike mixin

Remove the empty mixin left behind after deleting the deprecated copyWith methods.

BREAKING CHANGE: SentryEventLike is no longer exported.

Co-Authored-By: Codex <noreply@openai.com>

---------

Co-authored-by: Codex <noreply@openai.com>

* feat(profiling): Remove SDK profiling (#3891)

* feat(profiling)!: Remove SDK profiling

Remove transaction profiling configuration, lifecycle hooks, envelope
payloads, native bridges, and generated Cocoa bindings.

BREAKING CHANGE: SentryFlutterOptions.profilesSampleRate and SDK
profiling are no longer available.

Co-Authored-By: Codex <noreply@openai.com>

* test(flutter): Remove redundant profiling test

The removed API test only re-proves Dart's NoSuchMethodError behavior. Keep the profiling removal focused on SDK-owned behavior.

Co-Authored-By: Codex <noreply@openai.com>

---------

Co-authored-by: Codex <noreply@openai.com>

* feat(flutter): Remove CocoaPods support and update Sentry Cocoa to `9.21.0` (#3879)

* feat(flutter)!: Remove CocoaPods support

Update sentry-cocoa to 9.21.0 and adopt its structured hybrid SDK
interfaces. Support Sentry Flutter through Swift Package Manager only.

BREAKING CHANGE: Sentry Flutter no longer supports CocoaPods on iOS
or macOS. Use Swift Package Manager.

Co-Authored-By: Codex <noreply@openai.com>

* ref(flutter): Address Cocoa review feedback

Clarify native address and nullability intent.

Link the integration TODO and align documented SDK versions with CI.

Co-Authored-By: Codex <noreply@openai.com>

* fix(flutter): Handle missing replay ID

Treat a null replay capture result as an empty Sentry ID instead of
raising a type cast error. Cover the native channel fallback with a
regression test.

Co-Authored-By: Codex <noreply@openai.com>

---------

Co-authored-by: Codex <noreply@openai.com>

* ref(flutter): Share Darwin plugin sources (#3922)

Use Flutter's sharedDarwinSource layout instead of maintaining macOS
symlinks to the iOS Swift package.

Fixes #1445

Co-authored-by: GPT-5.6 Sol <noreply@openai.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* deps(flutter): Increase `jni` range and set `jnigen` to `0.17.0` (#3931)

* build(flutter): Relax jni pin, bump jnigen 0.17.0

Replace the exact `jni: 1.0.0` pin with `>=1.0.0 <1.1.0` and bump
jnigen to 0.17.0, regenerating the Android bindings.

An exact pin propagates resolution conflicts to every consumer that
also depends on jni. A range avoids that while still gating minors:
jnigen stamps `JniVersionCheck(1, 0)` into the bindings, which only
asserts major equality and a minor floor, so it cannot detect a
break introduced within 1.x. Capping below 1.1.0 turns each minor
into a Dependabot PR that the Android emulator integration tests
validate before it ships, while patches flow through automatically.

jnigen 0.17.0 defaults `generateStubs` to true, so referenced but
excluded Java classes now get minimal stubs instead of falling back
to JObject. That grows binding.dart by ~5k lines and takes the
generated extension types from 87 to 278; nothing is removed. The
version check stamp is unchanged at (1, 0).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style(flutter): Reformat bindings with Dart 3.12

`packages/flutter` declares `sdk: >=3.12.0`, and CI's analyze gate
formats it with the Flutter-bundled dart, so Dart 3.12's dart_style
is authoritative here. The previous commit was formatted with a
system Dart 3.10, which disagrees on this file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* build(flutter): Fix microbenchmarks jni resolution

microbenchmarks declared `jni: ^0.14.0` while depending on
sentry_flutter by path, which has required jni 1.x since the 1.0.0
migration. The two ranges do not overlap, so `pub get` failed
outright -- and CI resolves this package as part of the flutter
analyze job.

Use `jni: any` rather than restating the range. The package is
`publish_to: none`, so the effective constraint comes from
sentry_flutter and cannot drift out of sync again. The dependency
stays declared because jni_bench.dart imports package:jni directly.

Also unbreak two things that had rotted alongside it:
`sentryScreenshotWidgetGlobalKey` is now hidden from the public
barrel file, so import it from source like the neighbouring
widget_filter import, and reformat envelope_builder_bench.dart.

jni_bench.dart needed no changes for jni 1.x. Its local copy of
`_asUint8ListUnsafe` is kept rather than switched to the now-public
`asUint8List`, which adds a NewGlobalRef and a finalizer inside the
timed region and would change what the benchmark measures.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style(flutter): Format microbenchmark files

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* refactor: Remove options.log in favor of internalLogger (#3932)

* refactor: Remove options.log in favor of internalLogger

Replace the SdkLogCallback/options.log diagnostic path with
SentryInternalLogger across dart and flutter packages. Lazy log
callbacks are used where message construction may be expensive.

Co-Authored-By: Claude <noreply@anthropic.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* Potential fix for pull request finding

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

* fix(flutter): Use lazy callbacks for expensive log messages

Defer widget/exception toString until logging is enabled.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: Align Dart and Flutter SDK constraints

Every package, example and script now declares the same constraints
that packages/flutter already required: Dart >=3.12.0 <4.0.0 and
Flutter >=3.44.0. Previously only sentry_flutter had been bumped,
leaving the rest of the monorepo advertising support for Dart 3.5 /
Flutter 3.24 that v10 no longer targets.

Also moves the pinned min-version job in dart.yml off Dart 3.5 and
updates the prerequisites in CONTRIBUTING.md to match.

The grpc4 example gains the experimental_member_use ignore that grpc5
already had, matching its sibling.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* ref: Apply new linter rules and graduate experimental APIs (#3940)

* ref(api)!: Graduate experimental APIs

Stabilize mature Flutter and integration APIs for v10.
BindingWrapper and bindingUtils are now internal.

Refs #3827

BREAKING CHANGE: BindingWrapper and bindingUtils are internal.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style: Format affected packages

Use the CI Dart 3.12.2 formatter for affected packages.

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style(flutter): Use FVM formatting

Co-authored-by: Cursor <cursoragent@cursor.com>

* style: Resolve new analyzer hints

Co-authored-by: Cursor <cursoragent@cursor.com>

* Formatting

* Formatting

* Formatting

* style: Resolve CI analyzer hints

Co-Authored-By: GPT-5.6 Luna <noreply@openai.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: GPT-5.6 Luna <noreply@openai.com>

* Changelog for next release

* release: 10.0.0-alpha.3

* fix(http): Align HTTP client error type and value (#3934)

* fix(dio): Identify DioException when obfuscated

Under --obfuscate, DioException.runtimeType resolves to a minified
name such as Qx, which becomes the issue title. Register a
DioExceptionTypeIdentifier so the type stays readable without
requiring the obfuscation map upload.

packages/dart and packages/flutter already ship an identifier; dio
was the only integration without one.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Shorten verbose DioException values

A bad response renders as four lines of boilerplate: the meaning of
the status code, a link to MDN and generic remediation advice. Replace
it with the status code and route, which are what identify the
failure. The request URL and status code are already on the event, and
the untouched DioException stays on SentryException.throwable for
beforeSend.

Gated to the cases that carry no information of their own -
badResponse and a null message - so timeouts keep the duration that
elapsed and connection errors keep the host that failed. Skipped
entirely when the user set DioException.stringBuilder or the global
readableStringBuilder.

Fixes GH-2914

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Match failed request targets on full URL

failedRequestTargets was matched against requestOptions.path, which is
relative to baseUrl, so a host-based target like ['myapi.com'] never
matched and the request was silently not captured. Match on the
resolved URL instead, as FailedRequestClient does.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dart): Align HTTP client error type and value

SentryHttpClientError appeared in no ExceptionTypeIdentifier, so the
issue title obfuscated in release builds just like dio's did. Its
toString() also prefixed the message with 'Exception: ', which no
other SDK emits.

The value now reads exactly as sentry-javascript's does:
'HTTP Client Error with status code: 404'.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(supabase): Align client error type and value

SentrySupabaseClientError carried the same two problems as
SentryHttpClientError: no ExceptionTypeIdentifier, so the issue title
obfuscated, and an 'Exception: ' prefix on the value that no other SDK
emits.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Use spec wording for error value

The previous format repeated the exception type, which Sentry already
renders as the issue title prefix, and embedded the request path, making
the value vary per path parameter. Use the same string the HTTP client
spec, sentry-javascript and FailedRequestClient produce, so a Dio 502 and
a package:http 502 read identically. The route still travels on the
request interface.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix: Filter sensitive headers from the response context

SentryRequest sanitizes its headers, SentryResponse never did, so a
response's Set-Cookie, Authorization or X-API-Key was sent verbatim
whenever sendDefaultPii was on. Route both HTTP client paths through
HttpSanitizer.

SentryResponse derives its cookies field from the headers map, so the
cookie is now read before sanitizing to keep that field populated, which
matches how sentry-java's OkHttp interceptor treats it.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Capture connection-level failures

The interceptor required a status-code match, and a DioException without
a response has none, so timeouts, DNS errors and TLS failures produced no
event at all. FailedRequestClient captures the equivalent failures on the
package:http path.

A missing status code now means there is nothing to filter on rather than
an automatic reject. Cancellations stay excluded, being a deliberate user
action, and failedRequestTargets is still honoured.

Co-Authored-By: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Normalize connection failure messages

DioEventProcessor rewrote the exception value only for bad responses,
leaving timeouts and connection errors with Dio's own text. Those
messages restate the timeout the developer configured and append
generic remediation advice, and the embedded duration gave every
timeout setting its own issue title.

sentry-javascript never surfaces the underlying error's message
either: httpClientIntegration uses the error only to recover a stack
trace and always sets the value to its synthetic string. A timeout now
reads "HTTP Client Error: connectionTimeout".

A user-supplied stringBuilder still wins.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(http): Skip DSN requests, mark errors handled

Two gaps against the HTTP client spec and sentry-javascript, closed
across the package:http, dio and supabase integrations.

Requests to the DSN were captured like any other, so a failing
transport could try to report the failure over the connection that
just failed. sentry-javascript guards this with isSentryRequestUrl
inside _shouldCaptureResponse; the helper added here matches the DSN
host the same way.

The mechanism also left `handled` unset. It is now true: the SDK
caught the failure and reported it rather than letting it reach the
app. sentry-javascript sets false, which is deliberately not copied.
SentryEnvelope.fromEvent turns handled == false into
containsUnhandledException, which tells the native SDKs to end the
session as crashed, and captureFailedRequests defaults to true here
while httpClientIntegration is opt-in there. Copying that value would
report a crashed session for every captured 5xx.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* chore(example): Add Dio failure demo buttons

Three buttons covering the paths this branch touches: a 404 bad
response, a connection timeout and a DNS failure. The latter two were
dropped entirely before the interceptor learned to capture failures
that carry no status code.

Each swallows the DioException so the interceptor's event is the only
one sent, rather than a second one from an implicit capture.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Word connection failures in prose

A failure with no status code took its value straight from the enum
name, so issue titles read "HTTP Client Error: connectionTimeout" --
a leaked identifier. They now read "connection timeout", "connection
error", "bad certificate" and so on.

Only the types whose enum name reads badly are mapped; a type Dio adds
in a future minor release falls back to the name rather than breaking
the build, which a switch would.

The detail behind a connection error is not lost by keeping the title
generic: DioErrorExtractor already chains DioException.error as a
cause, so a DNS failure still carries its
"SocketException: Failed host lookup" on the event.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(http): Compare the DSN host exactly

The DSN skip tested whether the URL contained the DSN host, so a
self-hosted DSN on sentry.example.com also suppressed capture for
not-sentry.example.com. Failures on such a host went unreported with
nothing to indicate why.

Parse the URL and compare hosts instead. sentry-javascript's
isSentryRequestUrl has the same substring flaw; the cost of being
stricter is a Uri.tryParse per captured failure, and a relative URL
cannot address the DSN so it yields an empty host and is kept.

Reported by Bugbot on #3934.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dio): Keep the response body off the event

Putting the response on contexts.response also started shipping the
response body, which had previously been built but only ever reached
the beforeSend hint, and hints are never serialized. With
sendDefaultPii on, every failed request would carry up to 150 KB of
response body -- more than the option asks for, and more than
FailedRequestClient or the other SDKs send.

The event now gets status code, headers, cookies and body size. The
body stays on the hint, so beforeSend can still read it.

Reported by Bugbot on #3934.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* fix(dart): Drop a null status code from the mechanism

A request that threw reported mechanism.description as "HTTP Client
Error with status code: null". The reason string was built before
knowing whether it would be used: a thrown exception is kept as-is, so
only the synthesized SentryHttpClientError ever needs the description.

The exception value was never affected -- ??= short-circuits, so the
thrown ClientException and its own message stay in the title.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: Trim redundant comments

Drop comments that restate the code, duplicate the doc on
`isSentryRequestUrl`, repeat the same `handled: true` rationale in
three packages, or justify the change against sentry-javascript.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(dio): Cite Dio for the failure descriptions

Review feedback. Link the private toPrettyDescription() the map
mirrors, and note that an unlisted type falls back to its enum name so
a Dio release cannot break the build.

Adopt Dio's own "request cancelled" over "cancelled", and drop the
claim that a cancellation is a user action -- it comes from a
CancelToken, which app code or a wrapping library may hold.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style: Reformat for the new dart_style

v10-branch graduated to the newer formatting in #3940. The files this
branch touches were written against the previous style, so the merge
left them failing the format gate.

Formatting only; no behavior change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* style(supabase): Reformat for the new dart_style

Same as the previous commit -- a test this branch touches predates the
formatting v10-branch adopted in #3940.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

* build(flutter): Migrate to built-in Kotlin (#3961)

Stop applying the Kotlin Gradle Plugin from the Android plugin
project. Flutter 3.44+ applies KGP to library subprojects that
don't declare it, and sentry_flutter already requires Flutter
3.44, so the plugin no longer needs its own KGP classpath.

Replace kotlinOptions with the kotlin.compilerOptions DSL, which
requires KGP 2.0.0 -- the minimum enforced by Flutter 3.44. Drop
the explicit kotlin-stdlib-jdk8 dependency since KGP adds the
stdlib automatically.

Also bump the microbenchmarks KGP pin, which sat below the 2.0.0
floor.

Co-authored-by: Cursor <noreply@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>

* chore: Merge tag '9.27.0' into v10-branch (#3968)

* feat(replay): Add request details  to Session Replay on Android  (#3875)

* feat(replay): Add HTTP request/response capture

Adds opt-in capture of HTTP request/response headers and bodies for
Session Replay network breadcrumbs, gated by
enableReplayNetworkDetailsCapturing plus networkDetailAllowUrls/
networkDetailDenyUrls, scoped to Dart-only requests.

NetworkDetailsCapture (Dart) attaches the captured data to the http
breadcrumb, which the Android/iOS replay breadcrumb converters forward
into the RRWebSpanEvent unchanged.

Also syncs the network detail options into the native
SentryReplayOptions at init so the SDK reports
networkDetailHasUrls: true in the replay's options event - the Sentry
frontend gates rendering of captured request/response detail on that
flag, so without this sync the data would never show up in the
dashboard despite being captured correctly.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Scope HTTP detail capture to Android only

iOS session replay doesn't yet forward captured request/response
detail, so drop the unused iOS converter change and note the
Android-only support in the option docs.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Always forward fully-read response body

If decoding the captured response body threw, captureResponse
returned the original response whose stream was already drained
by toBytes(), silently dropping the body for the caller. Forward
the copied bytes regardless of whether the capture decode/truncate
step succeeds.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Gate network body capture behind sendDefaultPii

Request/response bodies frequently contain PII, so only collect
them when sendDefaultPii is enabled, matching the same gate used
by FailedRequestClient. Also register a SentryFeatures constant
and track it via options.sdk.addFeature so usage of this option
shows up in SDK analytics, per the code guidelines.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Gate custom headers behind sendDefaultPii too

Custom header names configured via networkRequestHeaders/
networkResponseHeaders (e.g. Authorization, Cookie) were captured
regardless of sendDefaultPii, only the default content-type-like
headers should be unconditional. Also mirror the same gate in the
Android native sync so setNetworkCaptureBodies and the custom
header lists can't bypass the Dart-side privacy check.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(replay): Order NetworkDetailsCapture fields before ctor

Reorders members to fields → constructor → public API → private
helpers, per review feedback.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(replay)!: Remove enableReplayNetworkDetailsCapturing

Only Cocoa needs a separate enable flag; gate purely on
networkDetailAllowUrls being non-empty, matching other SDKs.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Truncate captured bodies via bytes, not strings

Avoids fully utf8-encoding the whole body just to check its size:
_truncateBytes slices the Uint8List first, then decodes once. Also
reads the request body via bodyBytes instead of the decoded body
string.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Skip oversized response bodies before reading

Checks response.contentLength against maxBodySize upfront, avoiding
buffering a body we already know will be discarded past the size
we'd truncate it to anyway.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Bound response body buffering to maxBodySize

Reading via toBytes() buffered the entire response before
truncating, so a large or unbounded chunked body (no
Content-Length) was fully materialized in memory even though
only maxBodySize is ever captured. Add bufferStreamPrefix, which
reads only up to the cap and replays the rest of the stream
lazily to the original caller.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Bound single-chunk overshoot and oversized request bodies

bufferStreamPrefix appended each chunk in full before checking
the cap, so one chunk larger than maxBytes still buffered past
it. Slice the overflowing chunk at the boundary and replay the
remainder instead.

Also align request body capture with the response path: skip
attaching the body entirely when it's already known to exceed
maxBodySize, rather than attaching a truncated fragment.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Cancel source stream when replay forwarding stops early

bufferStreamPrefix's replay() generator never cancelled the source
StreamIterator if the forwarded stream was dropped or only partially
consumed (e.g. an early-aborted response body), leaking the
underlying subscription. Wrap the generator body in try/finally so
the iterator is always cancelled on exit.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Capture request headers after dispatch

Request headers were snapshotted before `_client.send()`, so
mutations made by clients further down the chain (e.g. TracingClient
adding sentry-trace/baggage headers) were missed. Move the capture
into the finally block so it reflects headers as actually sent.

Co-Authored-By: Claude <noreply@anthropic.com>

* revert(replay): Drop stream-buffering optimization for response bodies

Buenaflor asked to defer this to keep review scope focused on the
replay-only breadcrumb-leak issue (getsentry/sentry-dart#3900) instead.
Reverts 27b7c5b5, cb9bba37 (stream_utils.dart portion), and 7f5bcc52;
keeps the request-body length-gate fix from cb9bba37, which is
independent of the streaming optimization.

This reverts the bufferStreamPrefix helper and restores
response.stream.toBytes() in NetworkDetailsCapture.captureResponse.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(replay): Move HTTP capture options under options.replay

Groups networkDetailAllowUrls/DenyUrls, networkCaptureBodies, and
networkRequestHeaders/ResponseHeaders under a new SentryReplayOptions
in core, with SentryFlutterOptions.replay extending it, instead of
sitting flat on SentryOptions.

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor(replay): Move HTTP capture impl under sentry_flutter

Network capture for replay is a Flutter-only concern; sentry (dart)
now only exposes an internal NetworkDetailsCapture interface plus a
nullable hook on SentryOptions, mirroring the Transport seam.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Set capture feature flag lazily, not in ctor

FlutterNetworkDetailsCapture is built in _initDefaultValues, before
the user's optionsConfiguration runs, so networkDetailAllowUrls was
always empty at construction and the feature flag never got set.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Rethrow on response body capture failure

Returning the original response after a failed stream read left
callers reading an already-consumed stream, masking the real error
behind a confusing "already listened to" failure.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Stop breadcrumb timer before capturing body

Stopping the stopwatch in `finally` meant response body capture
(which can take arbitrarily long) was counted as request duration
for allow-listed URLs, while uncaptured requests only measured
time-to-headers. Stop it right after headers arrive instead.

Co-Authored-By: Claude <noreply@anthropic.com>

* test(replay): Pin expected body length as a literal

Asserting against FlutterNetworkDetailsCapture.maxBodySize makes the
test tautological: it can't fail if that constant itself were wrong,
since it's the same value the production truncation logic uses.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Don't mark a successful request as an error

A failure in captureResponse (e.g. reading the response stream for
replay) was caught by the same handler as a failed _client.send,
which set requestHadException and forced the http breadcrumb to
error level even though the request itself succeeded. Only a
transport-level failure should do that; a capture failure after a
real response now leaves the breadcrumb level based on status code.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Anchor breadcrumb timestamp to header arrival

Breadcrumb.http derives start_timestamp/end_timestamp from its
timestamp param, which defaulted to "now" at breadcrumb construction
in the outer finally - after response body capture completes. Once
requestDuration stopped covering that capture time, both timestamps
drifted by however long capture took instead of anchoring to when
headers actually arrived, shifting Session Replay network spans to
the end of body download.

Co-Authored-By: Claude <noreply@anthropic.com>

* fix(replay): Use injectable clock for breadcrumb timestamp

getUtcDateTime() reads the system clock directly, unlike the rest
of the SDK (e.g. Hub), which goes through SentryOptions.clock so
it's fakeable in tests. Switch BreadcrumbClient to the same pattern
and rewrite the timestamp regression test to assert call order via
an injected clock instead of comparing against real wall-clock time.

Co-Authored-By: Claude <noreply@anthropic.com>

* docs(flutter): Note networkDetailAllowUrls is Android-only

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-a…
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants