feat(client): prefetch and hydrate in-app feeds for SSR#1007
Conversation
The in-app feed only renders after the client hydrates and fetches it itself, so the notification surface flashes a skeleton on first paint even when the server already had the data. Add FeedClient.prefetch() to fetch a feed server-side and an initialData feed option (a FeedResponse or a promise of one) to seed the store from it, so frameworks can stream the feed down with the initial render. Modeled on TanStack Query's prefetch/initialData/hydrate.
🦋 Changeset detectedLatest commit: 048cd17 The changes in this PR will be included in the next version bump. This PR includes changesets to release 11 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
@gu-stav is attempting to deploy a commit to the Knock Team on Vercel. A member of the Team first needs to authorize it. |
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 048cd17. Configure here.
| method: "GET", | ||
| url: `/v1/users/${this.knock.userId}/feeds/${this.feedId}`, | ||
| params: queryParams, | ||
| params: buildFeedRequestParams(this.defaultOptions, options), |
There was a problem hiding this comment.
Fetch loading hides synced data
Medium Severity
When initialData is a resolved FeedResponse, hydration sets the store to ready with items, but a first-page fetch() still sets networkStatus to loading. UIs that hide feed items while status is loading can drop server-seeded content until the request completes, which conflicts with rendering hydrated data on first paint.
Reviewed by Cursor Bugbot for commit 048cd17. Configure here.


Description
The in-app feed is usually the first thing people look at — the notification list, the unread badge. It's also the one part of the page that can't render on the server. Everything around it streams down with the initial HTML, then the feed sits as a skeleton until the client boots, authenticates, and makes its own round-trip to Knock. On a cold load that's the slowest pixel on the screen, and it's the one users came for.
The reason it's stuck client-side is that there's no supported way to hand a server-fetched feed to the client. You can fetch it on the server, but the SDK has no entry point to render from it — so teams either live with the skeleton flash or call the REST API directly and rebuild the response shape by hand, which quietly drifts from what the client expects and breaks the moment realtime reconciles.
This closes that gap.
FeedClient.prefetch()fetches a feed on the server without spinning up a feed instance or a socket, and a newinitialDatafeed option seeds the store from that response — or from a still-pending promise, so a loader can kick off the request without awaiting it and let the framework stream the result down. The feed paints with real content on first render. Because prefetch sends the exact same request the client would have, there's no flash when the live connection takes over.It's modeled on TanStack Query's
prefetchQuery/initialData/hydrate, so it lands on a mental model most people already carry. Fully opt-in and backwards compatible — leave the option off and nothing changes; the feed still connects and reconciles exactly as before.Checklist