Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions packages/router-ssr-query-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import {
import { isRedirect } from '@tanstack/router-core'
import type { AnyRouter } from '@tanstack/router-core'
import type {
DehydrateOptions,
HydrateOptions,
QueryClient,
DehydratedState as QueryDehydratedState,
} from '@tanstack/query-core'
Expand All @@ -20,6 +22,8 @@ export type RouterSsrQueryOptions<TRouter extends AnyRouter> = {
* @link [Guide](https://tanstack.com/router/latest/docs/framework/react/api/router/redirectFunction)
*/
handleRedirects?: boolean
hydrateOptions?: Omit<HydrateOptions, 'shouldDehydrateQuery'>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix the hydrateOptions type definition to avoid potential issues.

The shouldDehydrateQuery property should not be omitted from HydrateOptions. According to the TanStack Query API, HydrateOptions does not include a shouldDehydrateQuery property - that property belongs to DehydrateOptions. This appears to be a copy-paste error.

Apply this diff to fix the type:

-  hydrateOptions?: Omit<HydrateOptions, 'shouldDehydrateQuery'>
+  hydrateOptions?: HydrateOptions
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hydrateOptions?: Omit<HydrateOptions, 'shouldDehydrateQuery'>
hydrateOptions?: HydrateOptions
🤖 Prompt for AI Agents
In packages/router-ssr-query-core/src/index.ts around line 25, the
hydrateOptions type currently omits 'shouldDehydrateQuery' which is incorrect
because HydrateOptions does not include that property (it's on
DehydrateOptions); change the type so hydrateOptions is either HydrateOptions or
a partial/omit that excludes only properties that actually exist on
HydrateOptions (remove the Omit<..., 'shouldDehydrateQuery'> wrapper) or
explicitly type it as HydrateOptions | Partial<HydrateOptions> depending on
desired optionality, ensuring the type no longer references
'shouldDehydrateQuery'.

dehydrateOptions?: DehydrateOptions
}

type DehydratedRouterQueryState = {
Expand All @@ -31,6 +35,8 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
router,
queryClient,
handleRedirects = true,
dehydrateOptions,
hydrateOptions,
}: RouterSsrQueryOptions<TRouter>) {
const ogHydrate = router.options.hydrate
const ogDehydrate = router.options.dehydrate
Expand All @@ -50,7 +56,10 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
queryStream: queryStream.stream,
}

const dehydratedQueryClient = queryDehydrate(queryClient)
const dehydratedQueryClient = queryDehydrate(
queryClient,
dehydrateOptions,
)
if (dehydratedQueryClient.queries.length > 0) {
dehydratedQueryClient.queries.forEach((query) => {
sentQueries.add(query.queryHash)
Expand Down Expand Up @@ -93,6 +102,7 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
sentQueries.add(event.query.queryHash)
queryStream.enqueue(
queryDehydrate(queryClient, {
...dehydrateOptions,
shouldDehydrateQuery: (query) => {
if (query.queryHash === event.query.queryHash) {
return (
Expand All @@ -110,15 +120,19 @@ export function setupCoreRouterSsrQueryIntegration<TRouter extends AnyRouter>({
await ogHydrate?.(dehydrated)
// hydrate the query client with the dehydrated data (if it was dehydrated on the server)
if (dehydrated.dehydratedQueryClient) {
queryHydrate(queryClient, dehydrated.dehydratedQueryClient)
queryHydrate(
queryClient,
dehydrated.dehydratedQueryClient,
hydrateOptions,
)
}

// read the query stream and hydrate the queries as they come in
const reader = dehydrated.queryStream.getReader()
reader
.read()
.then(async function handle({ done, value }) {
queryHydrate(queryClient, value)
queryHydrate(queryClient, value, hydrateOptions)
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick

Add null/undefined check before hydrating streamed values.

When reading from the query stream, the value could potentially be undefined in edge cases (e.g., if the stream is closed prematurely or contains no data). This could cause queryHydrate to fail silently or throw an error.

Apply this diff to add a safety check:

-          queryHydrate(queryClient, value, hydrateOptions)
+          if (value) {
+            queryHydrate(queryClient, value, hydrateOptions)
+          }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
queryHydrate(queryClient, value, hydrateOptions)
if (value) {
queryHydrate(queryClient, value, hydrateOptions)
}
🤖 Prompt for AI Agents
In packages/router-ssr-query-core/src/index.ts around line 135, the call to
queryHydrate(queryClient, value, hydrateOptions) needs a null/undefined guard
because streamed values may be undefined; update the code to check if value !==
null && value !== undefined (or use value != null) before calling queryHydrate,
and skip or safely handle/return when the value is missing (optionally log or
noop) to prevent errors from attempting to hydrate an empty value.

if (done) {
return
}
Expand Down