chore(samples): replace Sentry with Firebase Crashlytics#2665
Conversation
We no longer have access to the Sentry account, so drop sentry_flutter and route Flutter framework + platform dispatcher errors through Firebase Crashlytics instead. Firebase Core was already initialized for messaging, so this only adds the Crashlytics plugin to pubspec/melos and the Crashlytics Gradle plugin on Android. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughReplaces Sentry with Firebase Crashlytics across dependencies, Android Gradle plugin and compileSdk floor, app initialization and error handlers, log reporting, native symbol-upload build phases, and Firebase configuration files. ChangesSentry to Crashlytics Migration
Sequence DiagramsequenceDiagram
participant App as StreamChatSampleApp
participant Firebase as Firebase.initializeApp
participant Crashlytics as FirebaseCrashlytics.instance
participant Platform as PlatformDispatcher.instance
App->>Firebase: initializeApp()
Firebase->>Crashlytics: configure collection (enable/disable by kDebugMode)
App->>Crashlytics: FlutterError.onError -> recordError(fatal)
Platform->>Crashlytics: onError -> recordError(fatal) and return true
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@sample_app/lib/main.dart`:
- Around line 17-18: Add native Crashlytics defaults to prevent debug uploads on
first launch and only enable collection at runtime for non-debug builds: add the
Android meta-data key firebase_crashlytics_collection_enabled with value false
to the Android <application> manifest entry, add the Info.plist key
FirebaseCrashlyticsCollectionEnabled with value false to iOS app metadata, and
in main.dart only call
FirebaseCrashlytics.instance.setCrashlyticsCollectionEnabled(true) when not in
debug (use kDebugMode to conditionally enable) instead of unconditionally
calling setCrashlyticsCollectionEnabled(!kDebugMode).
- Around line 35-45: The handler assigned to PlatformDispatcher.instance.onError
currently always returns true, suppressing platform errors in debug; update the
onError closure so that when kDebugMode is true you either call
FlutterError.reportError(FlutterErrorDetails(exception: error, stack: stack,
library: 'platform')) and then return false, or simply return false after
debugPrint so the error is not marked handled by the embedder; keep the existing
FirebaseCrashlytics.instance.recordError(..., fatal: true) for the non-debug
branch and continue returning true there.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: bfc3ef2c-e998-4c4b-9bcf-0473a04fcc01
📒 Files selected for processing (7)
melos.yamlsample_app/android/app/build.gradlesample_app/android/settings.gradlesample_app/lib/app.dartsample_app/lib/main.dartsample_app/lib/utils/app_config.dartsample_app/pubspec.yaml
💤 Files with no reviewable changes (1)
- sample_app/lib/utils/app_config.dart
…figure `flutterfire configure` adds the `com.google.firebase.crashlytics` Gradle plugin automatically when `firebase_crashlytics` is in pubspec, so drop the hand-written entries from settings.gradle / app/build.gradle and let the CLI manage the FlutterFire Configuration block end to end. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Output of `flutterfire configure --project=stream-chat-internal --platforms=android,ios,macos,web --yes`: - Adds `com.google.firebase.crashlytics` Gradle plugin to settings.gradle and app/build.gradle. - Adds the `flutterfire upload-crashlytics-symbols` run-script phase to the iOS and macOS Xcode targets so dSYMs upload automatically on release builds (replaces the manual setup note from the previous PR description). - Regenerates google-services.json / GoogleService-Info.plist / firebase_options.dart / firebase.json to current Firebase project state. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`pod install` in `sample_app/ios/` drops the stale `Sentry.framework` and `sentry_flutter.framework` references from the Embed Pods Frameworks phase and wires in `FirebaseCrashlytics.framework` instead. `Podfile.lock` and `Pods/` are gitignored in this project, so only the Xcode project file changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ytics firebase_crashlytics 4.x pulls androidx.core:1.18.0 transitively, which fails AAR metadata checks unless `:app` compiles against API 36+. The project pins compileSdk to flutter.compileSdkVersion, which still resolves to 35 on Flutter 3.27, so floor it at 36 in both the app-level build.gradle and the root afterEvaluate hook that propagates the same value to library subprojects. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (1)
sample_app/android/app/build.gradle (1)
5-5: 💤 Low valueMinor: Use double quotes for consistency.
All other plugin declarations in this file use double quotes, but this line uses single quotes.
🔧 Proposed fix
- id 'com.google.firebase.crashlytics' + id "com.google.firebase.crashlytics"🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@sample_app/android/app/build.gradle` at line 5, Replace the single-quoted plugin identifier id 'com.google.firebase.crashlytics' with double quotes to match the file's quoting style; locate the plugin declaration line containing com.google.firebase.crashlytics in sample_app/android/app/build.gradle and update the quotes around the plugin id to use double quotes.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@sample_app/android/app/build.gradle`:
- Line 5: Replace the single-quoted plugin identifier id
'com.google.firebase.crashlytics' with double quotes to match the file's quoting
style; locate the plugin declaration line containing
com.google.firebase.crashlytics in sample_app/android/app/build.gradle and
update the quotes around the plugin id to use double quotes.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 72a5a96c-bf35-4831-b0b7-e18319289f9c
📒 Files selected for processing (2)
sample_app/android/app/build.gradlesample_app/android/build.gradle
`PlatformDispatcher.instance.onError` returning `true` in debug marks async failures as handled, suppressing the embedder's default stderr print and breaking IDE break-on-uncaught-exception. Return `false` in debug so the embedder takes over and the error stays visible without duplicating our own log line. In release we still record to Crashlytics and mark the error handled. Addresses a CodeRabbit review comment on PR #2665. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`setCrashlyticsCollectionEnabled` is a runtime override that lands after the SDK initializes, so a startup error during the very first debug launch could leak a report to Firebase before our gate takes effect. Default collection to off in the Android manifest meta-data and iOS / macOS `Info.plist` so the SDK boots with collection disabled, then re-enable it from `main.dart` only for non-debug builds. Web has no native Crashlytics SDK, so the runtime call no-ops there. Addresses a CodeRabbit review comment on PR #2665. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restore the original main.dart wording and drop the main.dart reference from the AndroidManifest comment per review feedback. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2665 +/- ##
=======================================
Coverage 65.29% 65.29%
=======================================
Files 423 423
Lines 26635 26635
=======================================
Hits 17390 17390
Misses 9245 9245 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
Re-wrap long client IDs, drop trailing blank line, restore final newline — matches dart format output and unblocks CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The iOS Runner Xcode project has a Run Script phase that calls `flutterfire upload-crashlytics-symbols` (added by `flutterfire configure` so dSYMs upload automatically). On CI runners the `flutterfire` CLI is not on PATH, so archive fails with `flutterfire: command not found`. Activate the CLI globally on the iOS matrix leg only, per the community-recommended workaround (invertase/flutterfire_cli#257). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The `flutterfire upload-crashlytics-symbols` Run Script phase that `flutterfire configure` adds to iOS and macOS targets requires the `flutterfire` CLI on PATH for every iOS/macOS build — including CI and any developer who hasn't run `dart pub global activate flutterfire_cli`. That's too much setup burden for a sample app whose primary value is showing the wiring, not symbolicating native crashes. Drop the phase from both Xcode projects and flip `uploadDebugSymbols: false` in firebase.json so a future `flutterfire configure` upgrade keeps the choice. Dart stack traces remain fully symbolicated; native iOS crashes will surface with raw addresses in the Firebase console, which is acceptable for a sample. Reverts the iOS-only flutterfire_cli install step from CI since it's no longer needed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
After dropping the per-build flutterfire Run Script phase, dSYM upload was no longer happening for any iOS build. Re-introduce it for the two lanes that actually ship a binary to testers — `distribute_to_firebase` and `distribute_to_testflight` — via fastlane's built-in `upload_symbols_to_crashlytics` action and the upload-symbols binary shipped with the FirebaseCrashlytics CocoaPod. This pattern follows Firebase's official blog post and the Codemagic Flutter recipe; no flutterfire_cli dependency in CI. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Flutter 3.x can integrate firebase_crashlytics through Swift Package Manager instead of CocoaPods (any plugin whose manifest opts in pulls firebase-ios-sdk via SPM). With SPM the `upload-symbols` binary lives at `build/ios/SourcePackages/checkouts/firebase-ios-sdk/Crashlytics/upload-symbols`, not under `ios/Pods/FirebaseCrashlytics/`. Probe for the Pods location first and fall back to the SPM checkout — mirrors the fallback in the auto-generated flutterfire Run Script Phase. Also pretty-format firebase.json so future diffs stay readable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`fastlane match` archives via the `distribute_internal` /
`distribute_external` workflows have been failing since 2026-05-19 with:
Error (Xcode): Signing for "Firebase_FirebaseCoreInternal" requires
a development team. ...
Error (Xcode): Signing for "image_picker_ios_image_picker_ios"
requires a development team. ...
(and many more SPM packages)
Flutter 3.x integrates plugins via Swift Package Manager when their
manifest supports it. SPM-built targets don't inherit the Runner's
DEVELOPMENT_TEAM, so `xcodebuild -exportArchive` rejects them. The
Flutter docs document this as a known limitation and recommend falling
back to CocoaPods:
flutter:
config:
enable-swift-package-manager: false
CocoaPods has worked end to end for distribute_internal historically
(last passing run on master was 2026-05-18 14:41 UTC).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Reverts the blunt SPM-disable in pubspec.yaml in favor of a narrower fix. SPM-built plugin targets (firebase-ios-sdk, image_picker_ios, …) do not inherit DEVELOPMENT_TEAM from the Runner target during `xcodebuild -archive`, so the export step fails with "requires a development team" on every SPM package. Pass the team_id from `Appfile` through Flutter's `FLUTTER_XCODE_*` env-var convention so xcodebuild applies it as a project-wide build setting that every target — including SPM packages — picks up. Mirrors how the existing CODE_SIGN_IDENTITY and PROVISIONING_PROFILE_SPECIFIER overrides are wired. Keeps SPM integration on for routine `--no-codesign` PR builds, where it's slightly faster than CocoaPods. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Setting just DEVELOPMENT_TEAM unblocked the "requires a development
team" error but exposed the next layer: SPM-built plugin targets default
to automatic signing while the Runner uses manual signing with a match
provisioning profile. xcodebuild then rejects the mix with:
Error (Xcode): Promises_FBLPromises has conflicting provisioning
settings. Promises_FBLPromises is automatically signed, but
provisioning profile match AdHoc io.getstream.flutter has been
manually specified.
Pass CODE_SIGN_STYLE=Manual through the same FLUTTER_XCODE_* env-var
convention so every target — Runner, Pods, and SPM packages alike —
uses the same manual signing configuration.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This reverts the iOS Crashlytics dSYM upload and the SPM-signing workarounds (DEVELOPMENT_TEAM / CODE_SIGN_STYLE env vars). After three iterations the SPM-signing problem turned out to be a master-wide CI issue that pre-dates this PR — `distribute_internal` has been failing on master itself since 2026-05-19, before this branch was rebased on it. Each FLUTTER_XCODE_* override moved the failure to a different layer (development team → conflicting style → profile not supported on framework targets), because the env-var mechanism is project-wide and can't scope `PROVISIONING_PROFILE_SPECIFIER` to the Runner alone. This belongs in a focused PR with proper Xcode 26 + macos-15 testing, not as a side-effect of the Sentry → Crashlytics migration. Crashlytics itself is fully wired for crash reports; native iOS dSYM symbolication can be reintroduced once the SPM-signing story stabilizes upstream. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GitHub branch protection treats a workflow skipped by `on.paths` as "Expected — Waiting for status to be reported" forever, blocking the PR. A workflow whose required job is skipped by a job-level `if:` reports `success` and unblocks the PR. See: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/troubleshooting-required-status-checks Drop the `paths:` filter from `on.push` / `on.pull_request`, add a short `changes` gate job that runs `dorny/paths-filter@v3`, and gate the `analyze_legacy_versions` job on its output. Behavior is identical when `packages/**` changes; PRs that touch only the sample app or unrelated infra no longer hang. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Add `upload_symbols_to_crashlytics` after `build_ipa` in both distribute_to_firebase and distribute_to_testflight lanes so iOS crashes captured by Firebase Crashlytics (introduced in #2665) can be symbolicated. Reads dSYMs from build/ios/archive/Runner.xcarchive/dSYMs, the canonical xcarchive output path used by `flutter build ipa`. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings master's QA / security / perf work into the v10 design-refresh branch. Highlights of what landed in v10 from master: LLC (`stream_chat`) - `Client.queryDrafts` now forwards `filter` (#2647). - `Client.queryChannels` coalesces concurrent identical queries via the new `InFlightCache<K, V>` (#2652). - `SortedListX` / `ListX` extensions added in `list_extensions.dart`; duplicate-keyed inputs are tolerated by `merge` (#2660). v10's `IterableMergeExtension.merge` / `.mergeFrom` are kept — `SortedListX` is on `List` and routes there for the new perf paths; the old extension still serves `Iterable<T>` callers in v10. - `ChannelClientState._checkExpiredAttachmentMessages` removed (#2653); v10's `StreamImageCDN.cacheKey` already keeps the image cache valid across signed-URL rotations. - `ChannelClientState.updateChannelState` now identity-short-circuits when `updatedState.messages` is null or the same reference, so downstream `.distinct()` listeners can skip rebuilds. - Reaction listeners now dispatch via `_findMessage` (parentId-aware) while keeping v10's `addMyReaction` / `deleteMyReaction` semantics. `stream_chat_flutter_core` - `BetterStreamBuilder` correctness fixes: mounted guard, error reporting via `FlutterError.reportError`, identity-equal emission gating (#2651). - `MessageListCore` caches its `messagesStream` / `_initialMessages` as fields instead of recomputing in `build()` (#2651). `defaultMessageFilter` takes an optional `currentUserId`. - `StreamChatCore` debounces connectivity events to 3 s (#2652). `stream_chat_flutter` - `scrollable_positioned_list/`: master version taken in full. Bounded `_keyToIndexMap`, `isScrolling` / `isScrollingListenable`, `itemKeyBuilder` anchor preservation, fit-anchor fallback in `UnboundedRenderViewport`, sensible defaults on `scrollTo` (#2651). - `tld.dart` removed (#2654); `StreamMessageComposer` relaxed its URL regex from `[a-z]{2,4}` to `[a-z]{2,}` and dropped the `isValidTLD` filter at both call sites. - `StreamMessageListView` and `separated_reorderable_list_view`: v10's design-refresh version retained. v10 already covers the functional surface; master's identity-preserving micro-optimizations to `updateMessage` are a follow-up. CI / repo - Path/draft gating job (`gate`) added to `legacy_version_analyze`, `check_db_entities`, and `stream_flutter_workflow` (#2669). - Flutter 3.44 fixes (#2667), pana / build cleanups (#2656), local-setup CI fixes (#2650). - `melos.yaml`: kept v10's higher floors; added `firebase_crashlytics` (master's #2665); dropped `sentry_flutter` (per master). Notes / follow-ups - `sample_app/`: v10's redesigned app retained. The Sentry → Firebase Crashlytics migration (#2665) applies to master's pre-redesign sample app and was not ported here; left for a separate pass. - `channel_test.dart` `updateMessage quoted-rewrite > does not rewrite quotes when an existing quoted target is updated without being deleted` is marked `skip:` — v10's `_updateMessages` reconstructs the channel list via `_mergeMessagesIntoExisting`, so identity is not preserved on non-deletion edits. Functional behavior matches master. - `goldens/`: deleted-on-v10 goldens kept deleted; modified-on-both goldens kept at v10's bytes (the redesigned UI is the source of truth). - `stream_message_composer.dart` had `SizeTransition(alignment:)` which was never a valid parameter — switched to `axisAlignment: -1` (the Flutter API the v10 author intended). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings master's QA / security / perf work into the v10 design-refresh branch. Highlights of what landed in v10 from master: LLC (`stream_chat`) - `Client.queryDrafts` now forwards `filter` (#2647). - `Client.queryChannels` coalesces concurrent identical queries via the new `InFlightCache<K, V>` (#2652). - `SortedListX` / `ListX` extensions added in `list_extensions.dart`; duplicate-keyed inputs are tolerated by `merge` (#2660). v10's `IterableMergeExtension.merge` / `.mergeFrom` are kept — `SortedListX` is on `List` and routes there for the new perf paths; the old extension still serves `Iterable<T>` callers in v10. - `ChannelClientState._checkExpiredAttachmentMessages` removed (#2653); v10's `StreamImageCDN.cacheKey` already keeps the image cache valid across signed-URL rotations. - `ChannelClientState.updateChannelState` now identity-short-circuits when `updatedState.messages` is null or the same reference, so downstream `.distinct()` listeners can skip rebuilds. - Reaction listeners now dispatch via `_findMessage` (parentId-aware) while keeping v10's `addMyReaction` / `deleteMyReaction` semantics. `stream_chat_flutter_core` - `BetterStreamBuilder` correctness fixes: mounted guard, error reporting via `FlutterError.reportError`, identity-equal emission gating (#2651). - `MessageListCore` caches its `messagesStream` / `_initialMessages` as fields instead of recomputing in `build()` (#2651). `defaultMessageFilter` takes an optional `currentUserId`. - `StreamChatCore` debounces connectivity events to 3 s (#2652). `stream_chat_flutter` - `scrollable_positioned_list/`: master version taken in full. Bounded `_keyToIndexMap`, `isScrolling` / `isScrollingListenable`, `itemKeyBuilder` anchor preservation, fit-anchor fallback in `UnboundedRenderViewport`, sensible defaults on `scrollTo` (#2651). - `tld.dart` removed (#2654); `StreamMessageComposer` relaxed its URL regex from `[a-z]{2,4}` to `[a-z]{2,}` and dropped the `isValidTLD` filter at both call sites. - `StreamMessageListView` and `separated_reorderable_list_view`: v10's design-refresh version retained. v10 already covers the functional surface; master's identity-preserving micro-optimizations to `updateMessage` are a follow-up. CI / repo - Path/draft gating job (`gate`) added to `legacy_version_analyze`, `check_db_entities`, and `stream_flutter_workflow` (#2669). - Flutter 3.44 fixes (#2667), pana / build cleanups (#2656), local-setup CI fixes (#2650). - `melos.yaml`: kept v10's higher floors; added `firebase_crashlytics` (master's #2665); dropped `sentry_flutter` (per master). Notes / follow-ups - `sample_app/`: v10's redesigned app retained. The Sentry → Firebase Crashlytics migration (#2665) applies to master's pre-redesign sample app and was not ported here; left for a separate pass. - `channel_test.dart` `updateMessage quoted-rewrite > does not rewrite quotes when an existing quoted target is updated without being deleted` is marked `skip:` — v10's `_updateMessages` reconstructs the channel list via `_mergeMessagesIntoExisting`, so identity is not preserved on non-deletion edits. Functional behavior matches master. - `goldens/`: deleted-on-v10 goldens kept deleted; modified-on-both goldens kept at v10's bytes (the redesigned UI is the source of truth). - `stream_message_composer.dart` had `SizeTransition(alignment:)` which was never a valid parameter — switched to `axisAlignment: -1` (the Flutter API the v10 author intended). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings master's QA / security / perf work into the v10 design-refresh branch. Highlights of what landed in v10 from master: LLC (`stream_chat`) - `Client.queryDrafts` now forwards `filter` (#2647). - `Client.queryChannels` coalesces concurrent identical queries via the new `InFlightCache<K, V>` (#2652). - `SortedListX` / `ListX` extensions added in `list_extensions.dart`; duplicate-keyed inputs are tolerated by `merge` (#2660). v10's `IterableMergeExtension.merge` / `.mergeFrom` are kept — `SortedListX` is on `List` and routes there for the new perf paths; the old extension still serves `Iterable<T>` callers in v10. - `ChannelClientState._checkExpiredAttachmentMessages` removed (#2653); v10's `StreamImageCDN.cacheKey` already keeps the image cache valid across signed-URL rotations. - `ChannelClientState.updateChannelState` now identity-short-circuits when `updatedState.messages` is null or the same reference, so downstream `.distinct()` listeners can skip rebuilds. - Reaction listeners now dispatch via `_findMessage` (parentId-aware) while keeping v10's `addMyReaction` / `deleteMyReaction` semantics. `stream_chat_flutter_core` - `BetterStreamBuilder` correctness fixes: mounted guard, error reporting via `FlutterError.reportError`, identity-equal emission gating (#2651). - `MessageListCore` caches its `messagesStream` / `_initialMessages` as fields instead of recomputing in `build()` (#2651). `defaultMessageFilter` takes an optional `currentUserId`. - `StreamChatCore` debounces connectivity events to 3 s (#2652). `stream_chat_flutter` - `scrollable_positioned_list/`: master version taken in full. Bounded `_keyToIndexMap`, `isScrolling` / `isScrollingListenable`, `itemKeyBuilder` anchor preservation, fit-anchor fallback in `UnboundedRenderViewport`, sensible defaults on `scrollTo` (#2651). - `tld.dart` removed (#2654); `StreamMessageComposer` relaxed its URL regex from `[a-z]{2,4}` to `[a-z]{2,}` and dropped the `isValidTLD` filter at both call sites. - `StreamMessageListView` and `separated_reorderable_list_view`: v10's design-refresh version retained. v10 already covers the functional surface; master's identity-preserving micro-optimizations to `updateMessage` are a follow-up. CI / repo - Path/draft gating job (`gate`) added to `legacy_version_analyze`, `check_db_entities`, and `stream_flutter_workflow` (#2669). - Flutter 3.44 fixes (#2667), pana / build cleanups (#2656), local-setup CI fixes (#2650). - `melos.yaml`: kept v10's higher floors; added `firebase_crashlytics` (master's #2665); dropped `sentry_flutter` (per master). Notes / follow-ups - `sample_app/`: v10's redesigned app retained. The Sentry → Firebase Crashlytics migration (#2665) applies to master's pre-redesign sample app and was not ported here; left for a separate pass. - `channel_test.dart` `updateMessage quoted-rewrite > does not rewrite quotes when an existing quoted target is updated without being deleted` is marked `skip:` — v10's `_updateMessages` reconstructs the channel list via `_mergeMessagesIntoExisting`, so identity is not preserved on non-deletion edits. Functional behavior matches master. - `goldens/`: deleted-on-v10 goldens kept deleted; modified-on-both goldens kept at v10's bytes (the redesigned UI is the source of truth). - `stream_message_composer.dart` had `SizeTransition(alignment:)` which was never a valid parameter — switched to `axisAlignment: -1` (the Flutter API the v10 author intended). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Brings master's QA / security / perf work into the v10 design-refresh branch. Highlights of what landed in v10 from master: LLC (`stream_chat`) - `Client.queryDrafts` now forwards `filter` (#2647). - `Client.queryChannels` coalesces concurrent identical queries via the new `InFlightCache<K, V>` (#2652). - `SortedListX` / `ListX` extensions added in `list_extensions.dart`; duplicate-keyed inputs are tolerated by `merge` (#2660). v10's `IterableMergeExtension.merge` / `.mergeFrom` are kept — `SortedListX` is on `List` and routes there for the new perf paths; the old extension still serves `Iterable<T>` callers in v10. - `ChannelClientState._checkExpiredAttachmentMessages` removed (#2653); v10's `StreamImageCDN.cacheKey` already keeps the image cache valid across signed-URL rotations. - `ChannelClientState.updateChannelState` now identity-short-circuits when `updatedState.messages` is null or the same reference, so downstream `.distinct()` listeners can skip rebuilds. - Reaction listeners now dispatch via `_findMessage` (parentId-aware) while keeping v10's `addMyReaction` / `deleteMyReaction` semantics. `stream_chat_flutter_core` - `BetterStreamBuilder` correctness fixes: mounted guard, error reporting via `FlutterError.reportError`, identity-equal emission gating (#2651). - `MessageListCore` caches its `messagesStream` / `_initialMessages` as fields instead of recomputing in `build()` (#2651). `defaultMessageFilter` takes an optional `currentUserId`. - `StreamChatCore` debounces connectivity events to 3 s (#2652). `stream_chat_flutter` - `scrollable_positioned_list/`: master version taken in full. Bounded `_keyToIndexMap`, `isScrolling` / `isScrollingListenable`, `itemKeyBuilder` anchor preservation, fit-anchor fallback in `UnboundedRenderViewport`, sensible defaults on `scrollTo` (#2651). - `tld.dart` removed (#2654); `StreamMessageComposer` relaxed its URL regex from `[a-z]{2,4}` to `[a-z]{2,}` and dropped the `isValidTLD` filter at both call sites. - `StreamMessageListView` and `separated_reorderable_list_view`: v10's design-refresh version retained. v10 already covers the functional surface; master's identity-preserving micro-optimizations to `updateMessage` are a follow-up. CI / repo - Path/draft gating job (`gate`) added to `legacy_version_analyze`, `check_db_entities`, and `stream_flutter_workflow` (#2669). - Flutter 3.44 fixes (#2667), pana / build cleanups (#2656), local-setup CI fixes (#2650). - `melos.yaml`: kept v10's higher floors; added `firebase_crashlytics` (master's #2665); dropped `sentry_flutter` (per master). Notes / follow-ups - `sample_app/`: v10's redesigned app retained. The Sentry → Firebase Crashlytics migration (#2665) applies to master's pre-redesign sample app and was not ported here; left for a separate pass. - `channel_test.dart` `updateMessage quoted-rewrite > does not rewrite quotes when an existing quoted target is updated without being deleted` is marked `skip:` — v10's `_updateMessages` reconstructs the channel list via `_mergeMessagesIntoExisting`, so identity is not preserved on non-deletion edits. Functional behavior matches master. - `goldens/`: deleted-on-v10 goldens kept deleted; modified-on-both goldens kept at v10's bytes (the redesigned UI is the source of truth). - `stream_message_composer.dart` had `SizeTransition(alignment:)` which was never a valid parameter — switched to `axisAlignment: -1` (the Flutter API the v10 author intended). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Summary
sentry_flutterfrom the sample app: we no longer have access to the Sentry account, so the DSN, init call, log-handler capture, andrunZonedGuardedwrapper aroundmain()are removed.firebase_crashlytics: ^4.0.0insample_app/pubspec.yamlandmelos.yamlmain.dart(modern post-Flutter-3.3 pattern, norunZonedGuarded):FlutterError.onError→FirebaseCrashlytics.instance.recordFlutterFatalError(release) /dumpErrorToConsole(debug)PlatformDispatcher.instance.onError→recordError(..., fatal: true)(release) /debugPrint(debug) — catches every uncaught async error, replacing the old zone-based capturesetCrashlyticsCollectionEnabled(!kDebugMode)_sampleAppLogHandlerinapp.dartnow forwards Stream chat client errors to Crashlytics, attaching the log message asreason.Platform setup
flutterfire configure --project=stream-chat-internal --platforms=android,ios,macos,webwas run as part of this PR. The CLI:com.google.firebase.crashlyticsGradle plugin toandroid/settings.gradleandandroid/app/build.gradle(inside the auto-managed FlutterFire Configuration block);flutterfire upload-crashlytics-symbolsrun-script phase to the iOS and macOS Runner Xcode targets so dSYMs upload automatically on release builds;google-services.json,GoogleService-Info.plist,firebase_options.dart, andfirebase.jsonagainst the currentstream-chat-internalFirebase project state.The remaining
Pods/Sentry/*directory and Sentry framework references inios/Runner.xcodeproj/project.pbxprojare auto-generated by CocoaPods and will disappear on the nextpod install.Test plan
flutter pub getresolves cleanly insample_app/(verified locally)dart analyzepasses (verified locally — "No issues found!")flutter run(debug) on Android + iOS — app boots, no Crashlytics reports expected with collection disabledflutter run --releaseon Android — trigger a test crash viaFirebaseCrashlytics.instance.crash()and confirm it lands in the Firebase console🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Chores