-
Notifications
You must be signed in to change notification settings - Fork 1
feat(llc): add onNewActivity callback to Feed
#65
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Introduces an `onNewActivity` callback to the `Feed` and `feedFromQuery` methods. This allows for custom logic to determine how new activities from real-time events are inserted into the activity list. The callback returns an `InsertionAction` (`addToStart`, `addToEnd`, or `ignore`). A default implementation is provided that adds activities from the current user to the start of the list if they match the query filter.
…activities to the end
WalkthroughAdds an onNewActivity callback and InsertionAction enum to control how new activities from events are inserted (start, end, or ignored); updates Feed, FeedEventHandler, feed creation APIs to accept the callback; moves many event handlers into an event/handler/ subdirectory and updates imports; adds tests and sample usage. Changes
Sequence DiagramsequenceDiagram
participant WS as WebSocket Event
participant Handler as FeedEventHandler
participant OnNew as onNewActivity Callback
participant State as FeedState
participant List as Activity List
WS->>Handler: ActivityAddedEvent arrives
Handler->>OnNew: onNewActivity(query, activity, currentUserId)
OnNew->>OnNew: Evaluate ownership & query filter
OnNew-->>Handler: InsertionAction (addToStart|addToEnd|ignore)
alt insertionAction == ignore
Handler->>Handler: Skip activity (no insertion)
else insertionAction == addToStart
Handler->>State: onActivityAdded(activity, insertionAction: addToStart)
State->>List: Insert at index 0
else insertionAction == addToEnd
Handler->>State: onActivityAdded(activity, insertionAction: addToEnd)
State->>List: Append to end
end
State-->>Handler: Activity processed / updated
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
packages/stream_feeds/lib/src/feeds_client.dart (1)
800-834:OnNewActivitytypedef anddefaultOnNewActivityfunction are not exported in the public API.The
OnNewActivitytypedef is used in the publicfeed()andfeedFromId()method signatures infeeds_client.dart, but it's not exported throughstate.dart. The filestate/on_activity_added.dartis missing from the export list inpackages/stream_feeds/lib/src/state.dart. Additionally,defaultOnNewActivityis marked@internaland should not be part of the public API. Add the export tostate.dart:export 'state/on_activity_added.dart';
🧹 Nitpick comments (5)
packages/stream_feeds/lib/src/state/insertion_action.dart (1)
1-13: Consider adding barrel file annotation.The enum is well-designed and clearly documented. However, since this is part of the public API (used by the
OnNewActivitycallback), consider marking it with@includeInBarrelFileannotation if it should be exported through the barrel file mechanism.Based on coding guidelines, public APIs should be marked with
@includeInBarrelFileannotation.packages/stream_feeds/lib/src/utils/filter.dart (1)
9-15: Consider narrowing the extension scope.While the extension is well-implemented with proper null-handling, extending all objects (
T extends Object) is quite broad and could lead to API pollution. Consider whether this extension could be more narrowly scoped to specific types that actually need filter matching (e.g.,ActivityData,CommentData) rather than all objects.If the current generic approach is intentional for reusability, this is acceptable. However, more targeted extensions would be clearer and less intrusive to the global namespace.
packages/stream_feeds/lib/src/state/event/on_activity_added.dart (1)
8-71:OnNewActivitycontract and default behavior align with requirementsThe typedef and
defaultOnNewActivityimplement the intended “add-if-from-current-user-and-matching-filter” default, giving consumers full control viaInsertionAction. As a tiny clean‑up, you could flatten the nestedifwithout changing behavior:- if (activity.user.id == currentUserId) { - if (activity.matches(query.activityFilter)) { - return InsertionAction.addToStart; - } - } - - return InsertionAction.ignore; + if (activity.user.id == currentUserId && + activity.matches(query.activityFilter)) { + return InsertionAction.addToStart; + } + + return InsertionAction.ignore;packages/stream_feeds/lib/src/state/feed_state.dart (1)
23-27:onActivityAddednow cleanly supports configurable insertionThe
InsertionActionparameter plusinsertAtcomputation and early return onignoregive a simple, extensible way to control placement while preserving the old default. Usingupsert(..., insertAt: (_) => insertAt)is a good fit to avoid duplicating list manipulation logic.If this method is a primary extension point, consider expanding its doc comment to briefly describe how
insertionActioninfluences ordering and how it relates toOnNewActivity, so future maintainers don’t have to chase the call chain.Also applies to: 111-133
packages/stream_feeds/lib/src/state/event/handler/feed_event_handler.dart (1)
3-18:FeedEventHandlercorrectly delegates ActivityAdded behavior toOnNewActivityWiring
onNewActivityinto the constructor and using it exclusively forActivityAddedEvent(while keepingmatchesQueryFilterfor other events) cleanly hands off insertion decisions to the callback and matches the new tests’ expectations. The sequence of:
- compute
InsertionAction,- call
state.onActivityAdded(...),- optionally enrich via
withUpdatedFeedCapabilities(...)
is straightforward and keeps capability updates orthogonal to insertion policy.One nuance worth keeping in mind (and which your tests already model) is that custom
onNewActivityimplementations are now solely responsible for honoringquery.activityFilterfor added activities; the previous automatic filter check no longer runs for this branch.Also applies to: 22-34, 48-58
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #65 +/- ##
==========================================
- Coverage 59.60% 59.52% -0.08%
==========================================
Files 120 121 +1
Lines 3758 3778 +20
==========================================
+ Hits 2240 2249 +9
- Misses 1518 1529 +11 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
packages/stream_feeds/test/state/feed_test.dart (1)
1827-1862: Consider adding a test for duplicate activity handling.The test suite covers the happy paths well. Consider adding a test case that verifies behavior when an
ActivityAddedEventarrives for an activity ID that already exists in the list. This would confirm whether the implementation prevents duplicates or updates existing activities.Would you like me to help draft a test case for the duplicate activity scenario?
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
📒 Files selected for processing (1)
packages/stream_feeds/test/state/feed_test.dart(4 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.dart
📄 CodeRabbit inference engine (.cursor/rules/cursor-rules-location.mdc)
**/*.dart: Use the barrel_files package with @includeInBarrelFile annotations for public API management in Dart projects; keep implementation details in lib/src/ without annotations
Mark only classes, functions, and enums intended for external package usage with @includeInBarrelFile; keep repository classes, mappers, and internal state objects in lib/src/ without annotations
**/*.dart: Use@freezedmixed mode for data classes in Dart
ReturnResult<T>from all repository methods in Dart
Apply early return patterns consistently in Dart code
Use pattern matching withswitchexpressions in Dart
Mark public APIs with@includeInBarrelFileannotation in Dart
Follow enhanced enum vs sealed class guidelines in Dart
Use const constructors where possible in Dart
Implement proper disposal patterns in Dart StateNotifiers and providers
Ensure pure Dart compatibility across VM, Flutter, and Web environments
Plan for StateNotifier reactive patterns when implementing state management in Dart
**/*.dart: Use @freezed for all data classes with required id fields and const constructors
Implement StateNotifier-based reactive state management with automatic change notifications
Apply Result pattern for all async operations with explicit error handling
Use early return patterns for clean control flow in Dart code
Create extension functions for data mapping using.toModel()pattern instead of mapper classes
Mark public APIs with @includeInBarrelFile annotation for barrel file export management
Implement proper resource management with disposal and cleanup patterns in Dart code
Use constructor injection for all dependencies in Dart classes
**/*.dart: All data models should use @freezed with Dart's mixed mode syntax and include @OverRide annotations on fields
Mark classes for public export using @includeInBarrelFile annotation
Use extension functions with.toModel()convention for data mapping instead of dedicated mapper classes
All repository methods must return Result...
Files:
packages/stream_feeds/test/state/feed_test.dart
packages/stream_feeds/test/**/*.dart
📄 CodeRabbit inference engine (AGENTS.md)
packages/stream_feeds/test/**/*.dart: Test through public APIs only, not internal StateNotifier implementations
Use HTTP interceptors instead of mocking repositories in tests
Mirror thelib/structure intest/directory organization
Files:
packages/stream_feeds/test/state/feed_test.dart
🧠 Learnings (15)
📓 Common learnings
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Stream Feeds API integration should be implemented according to the Activity Streams specification with structured actor, verb, object, and target fields
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Implement WebSocket event handlers for real-time Stream Feeds updates including activity events, reaction events, follow events, and member events
📚 Learning: 2025-12-05T14:37:17.519Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Stream Feeds API integration should be implemented according to the Activity Streams specification with structured actor, verb, object, and target fields
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/test/**/*.dart : Test through public APIs only, not internal StateNotifier implementations
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/test/**/*.dart : Use HTTP interceptors instead of mocking repositories in tests
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/src/models/**/*.dart : Query naming convention: Use `*Query` suffix for query classes (e.g., `ActivitiesQuery`, `FeedsQuery`)
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/src/models/**/*.dart : Request naming convention: Use `*Request` suffix for request classes (e.g., `FeedAddActivityRequest`)
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/stream_feeds.dart : Include examples for complex APIs in documentation
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/stream_feeds.dart : Keep public API minimal - most code should be in `lib/src/` internal directory
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/stream_feeds.dart : Follow Effective Dart documentation guidelines for all public APIs
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/stream_feeds.dart : Export public API classes from main library entry point `lib/stream_feeds.dart`
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/lib/stream_feeds.dart : Use `///` for public API documentation in exported classes and methods
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:38:02.662Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-05T14:38:02.662Z
Learning: Applies to packages/stream_feeds/test/**/*.dart : Mirror the `lib/` structure in `test/` directory organization
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:37:17.519Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Implement circuit breaker pattern for automatic failure recovery in Stream Feeds API interactions
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:37:17.519Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Implement proper authentication using API keys and user tokens via the StreamFeedsClient with tokenProvider parameter
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
📚 Learning: 2025-12-05T14:37:17.519Z
Learnt from: CR
Repo: GetStream/stream-feeds-flutter PR: 0
File: .cursor/rules/stream-feeds-api.mdc:0-0
Timestamp: 2025-12-05T14:37:17.519Z
Learning: Applies to {**/api/**/*.dart,**/*_api.dart,**/client/*.dart} : Implement WebSocket event handlers for real-time Stream Feeds updates including activity events, reaction events, follow events, and member events
Applied to files:
packages/stream_feeds/test/state/feed_test.dart
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: analyze
- GitHub Check: build
- GitHub Check: stream_feeds
🔇 Additional comments (4)
packages/stream_feeds/test/state/feed_test.dart (4)
755-759: LGTM!The
userIdparameter is correctly added to ensure activities are attributed to the current user, which is required for the defaultonNewActivitybehavior to insert them. This change maintains test correctness after the feature addition.
795-798: LGTM!Consistent with the other userId addition; ensures the no-filter test case works correctly with the default
onNewActivitybehavior.
1816-1825: Well-structured test suite with good coverage.The test group comprehensively covers the
onNewActivityfeature including:
- Default behavior for current user vs. other users
- Filter matching logic
- All three
InsertionActionvalues- Query/activity context usage in custom callbacks
2047-2056: Good demonstration of callback flexibility.This test effectively demonstrates how to compose custom insertion logic using query context and activity properties. The pattern of checking
activity.user.idandactivity.matches(query.activityFilter)provides a clear example for API consumers.
| // ignore_for_file: avoid_redundant_argument_values | ||
|
|
||
| import 'package:mocktail/mocktail.dart'; | ||
| import 'package:stream_feeds/src/utils/filter.dart'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Check if Filter and ActivitiesFilterField are exported from the main entry point
echo "=== Checking exports in stream_feeds.dart ==="
cat -n packages/stream_feeds/lib/stream_feeds.dart | grep -i "filter"
echo ""
echo "=== Checking filter.dart for @includeInBarrelFile annotation ==="
head -20 packages/stream_feeds/lib/src/utils/filter.dart | cat -n
echo ""
echo "=== Checking what's imported in the test file ==="
head -20 packages/stream_feeds/test/state/feed_test.dart | cat -n
echo ""
echo "=== Searching for Filter class definition ==="
rg -A 5 "^class Filter" packages/stream_feeds/lib/src/utils/filter.dart
echo ""
echo "=== Searching for ActivitiesFilterField ==="
rg "ActivitiesFilterField" packages/stream_feeds/lib/src/utils/filter.dart | head -5Repository: GetStream/stream-feeds-flutter
Length of output: 1779
🏁 Script executed:
#!/bin/bash
# Check what stream_feeds.dart exports and imports from stream_core
echo "=== Full content of stream_feeds.dart ==="
cat packages/stream_feeds/lib/stream_feeds.dart
echo ""
echo "=== Check if Filter is from stream_core ==="
rg "Filter" packages/stream_feeds/lib/src/utils/filter.dart -A 2 -B 2 | head -30Repository: GetStream/stream-feeds-flutter
Length of output: 840
🏁 Script executed:
#!/bin/bash
# Check what exactly the test file uses from filter.dart import
echo "=== Checking usage of filter.dart imports in the test ==="
rg "Filter|ActivitiesFilterField" packages/stream_feeds/test/state/feed_test.dart | head -20
echo ""
echo "=== Check if these extensions are used elsewhere in tests ==="
rg "toRequest|matches" packages/stream_feeds/test/state/feed_test.dart | head -10Repository: GetStream/stream-feeds-flutter
Length of output: 1376
Remove the direct import of internal filter utilities; use the public API instead.
The import at line 4 uses an internal path (src/utils/filter.dart). Tests should access Filter and related utilities through the public API. The Filter class and ActivitiesFilterField are available via package:stream_core/stream_core.dart, which is already exported from stream_feeds.dart. If the extension methods toRequest() and matches() are needed, they should be exported from the main library entry point with @includeInBarrelFile annotation rather than imported directly from internal paths.
Submit a pull request
Closes FLU-348
Description of the pull request
Introduces an
onNewActivitycallback to theFeedandfeedFromQuerymethods. This allows for custom logic to determine how new activities from real-time events are inserted into the activity list.The callback returns an
InsertionAction(addToStart,addToEnd, orignore).A default implementation is provided that adds activities from the current user to the start of the list if they match the query filter.
Important
Switch to pub dependency before merging the PR
Summary by CodeRabbit
New Features
Breaking Changes
Tests
✏️ Tip: You can customize this high-level summary in your review settings.