feat: Feed core — env-provisioned, input-driven paging/search engine - #233
Open
danieltmbr wants to merge 1 commit into
Open
feat: Feed core — env-provisioned, input-driven paging/search engine#233danieltmbr wants to merge 1 commit into
danieltmbr wants to merge 1 commit into
Conversation
The foundational layer for offline-first paged feeds. One call — .feed(.posts) — owns a FeedModel, wires its fetch pipeline from the environment, and scopes the model + FeedState + control actions for the subtree; children read the model back with @Feed(PostsQuery.self). - PageableQuery: the domain query itself drives the feed (isSearch/cursor/ page(after:)); conformances for Posts/Quotes/CatalogueSearch queries and an input-less CatalogueSyncQuery for the SyncGroup-backed catalogue refresh - FeedModel: fetch(input) is the one entry point — the input decides browse vs search vs continuation; page-1 supersedes in-flight requests and superseded callers converge on the winner's receipt (race-proof); continuations fail quietly; returns FeedPage receipts so the owning view keeps paging state - FeedConfiguration: label + composed fetch pipeline (loader → upsert → nextCursor), with real pipelines as statics and stub injection for previews - Self-contained components: FeedStatusLine, FeedLoadMoreCell, FeedEmptyView read \.feedState + \.loadFeed/\.retryFeed — nothing passed through inits - tmbr-core: query DTOs gain Hashable, page(after:), languages/sources params, and view-facing convenience inits; closure-based RequestLoader in app-api - Groundwork: CatalogueItemSyncDescriptor rename + .book descriptor fix, CatalogueSearchEngine, detail-section pre-work, test-target dependency and container-lifetime fixes Tabs are intentionally untouched — they migrate in the stacked follow-ups (blog → quotes → catalogue). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Foundational layer for offline-first paged feeds (stack 1/4 — see #229 for the full reference).
PageableQuery— the domain query drives the feed:isSearch/cursor/page(after:)conformances onPostsQuery/QuotesQuery/CatalogueSearchQuery, plus an input-lessCatalogueSyncQueryfor the SyncGroup-backed catalogue refreshFeedModel—fetch(input)is the one entry point; the input alone decides browse vs search vs continuation. Page-1 requests fire immediately and supersede in-flight ones; superseded callers converge on the winner's receipt so late resumptions can't clobber newer commits. Continuations fail quietly. Committed fetches returnFeedPagereceipts — the owning view keeps paging stateFeedConfiguration+.feed(_:)— one call provisions a subtree: owns the model, wires the pipeline fromapiBaseURL/urlSession/modelContext, persists the freshness stamp, scopes model/state/actionsFeedStatusLine/FeedLoadMoreCell/FeedEmptyViewread\.feedState+ action keys, nothing through initspage(after:), languages/sources params), closure-basedRequestLoader, descriptor-rename fixes, test-debt fixesTabs are intentionally untouched here — they migrate in the stacked follow-ups (blog → quotes → catalogue). Two surgical patches keep the old tabs compiling next to the new core (
LoadingStatemoved toFeedState; asecondaryInfounwrap in the old CatalogueTab).Verification
swift test --package-path app-core— 65 tests green (new FeedModel/FeedSeam suites + existing suites)🤖 Generated with Claude Code