feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

feat: use seroval for SSR - #4600

Merged
schiller-manuel merged 6 commits into
mainfrom
seroval
Jul 10, 2025
Merged

feat: use seroval for SSR#4600
schiller-manuel merged 6 commits into
mainfrom
seroval

Conversation

@schiller-manuel

Copy link
Copy Markdown
Collaborator

also stream all queries in react-router-with-query

also stream all queries in react-router-with-query
@nx-cloud

nx-cloudBot commented Jul 8, 2025

Copy link
Copy Markdown
Contributor

View your CI Pipeline Execution ↗ for commit 9220a3e

CommandStatusDurationResult
nx affected --targets=test:eslint,test:unit,tes...✅ Succeeded1m 31sView ↗
nx run-many --target=build --exclude=examples/*...✅ Succeeded6sView ↗

☁️ Nx Cloud last updated this comment at 2025-07-10 22:09:10 UTC

@pkg-pr-new

pkg-pr-newBot commented Jul 8, 2025

Copy link
Copy Markdown
More templates

@tanstack/arktype-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/arktype-adapter@4600

@tanstack/directive-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/directive-functions-plugin@4600

@tanstack/eslint-plugin-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/eslint-plugin-router@4600

@tanstack/history

npm i https://pkg.pr.new/TanStack/router/@tanstack/history@4600

@tanstack/react-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router@4600

@tanstack/react-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-devtools@4600

@tanstack/react-router-with-query

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-router-with-query@4600

@tanstack/react-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start@4600

@tanstack/react-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-client@4600

@tanstack/react-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-plugin@4600

@tanstack/react-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/react-start-server@4600

@tanstack/router-cli

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-cli@4600

@tanstack/router-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-core@4600

@tanstack/router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools@4600

@tanstack/router-devtools-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-devtools-core@4600

@tanstack/router-generator

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-generator@4600

@tanstack/router-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-plugin@4600

@tanstack/router-utils

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-utils@4600

@tanstack/router-vite-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/router-vite-plugin@4600

@tanstack/server-functions-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/server-functions-plugin@4600

@tanstack/solid-router

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router@4600

@tanstack/solid-router-devtools

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-router-devtools@4600

@tanstack/solid-start

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start@4600

@tanstack/solid-start-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-client@4600

@tanstack/solid-start-plugin

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-plugin@4600

@tanstack/solid-start-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/solid-start-server@4600

@tanstack/start-client-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-client-core@4600

@tanstack/start-plugin-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-plugin-core@4600

@tanstack/start-server-core

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-core@4600

@tanstack/start-server-functions-client

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-client@4600

@tanstack/start-server-functions-fetcher

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-fetcher@4600

@tanstack/start-server-functions-server

npm i https://pkg.pr.new/TanStack/router/@tanstack/start-server-functions-server@4600

@tanstack/valibot-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/valibot-adapter@4600

@tanstack/virtual-file-routes

npm i https://pkg.pr.new/TanStack/router/@tanstack/virtual-file-routes@4600

@tanstack/zod-adapter

npm i https://pkg.pr.new/TanStack/router/@tanstack/zod-adapter@4600

commit: 9220a3e

Comment threadpackages/react-router-with-query/src/index.tsx Outdated
Comment threadpackages/react-router-with-query/src/index.tsx Outdated
type: 'stream'
value?: ReadableStream & { controller?: ReadableStreamDefaultController }
export interface TsrSsrGlobal {
r?: DehydratedRouter

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

While it makes sense for the matches to have keys be shortened (i.e. i, b, l, etc.), I think these single callers may benefit from just being left with having descriptive names to represent their purpose (i.e. router/dehydratedRouter, close, whatever_v_is).

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

renamed r to router, v is gone
added a comment to c ( the cleanup function), this is called per script injection and thus benefits from a short name

import { isPlainObject } from '@tanstack/router-core'

export interface TsrSerializer {
export interface StartSerializer {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why does the Serializer get moved to Start? why not keep it in router-core.

Wouldn't this same serializer benefit normal basic-file-based-ssr-streaming as well?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

this PR only uses seroval for SSR
for server functions, we still use the old serializer. in a followup PR, we'll move server functions over to seroval as well

@schiller-manuel
schiller-manuel merged commit 6475b35 into mainJul 10, 2025
@schiller-manuel
schiller-manuel deleted the seroval branch July 10, 2025 22:25
hydrate as queryHydrate,
} from '@tanstack/react-query'
import { isRedirect } from '@tanstack/router-core'
import '@tanstack/router-core/ssr/client'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like extra import

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

what's the issue here?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Is this intended to import this module like side effect without import specific functions, etc?

Copy link
Copy Markdown
CollaboratorAuthor

Choose a reason for hiding this comment

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

the import is necessary to get the type import. is there any problem with that import?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sorry for disturbing.
I expected to see something like:

import { type SomeType } from '@tanstack/router-core/ssr/client'

instead of import '@tanstack/router-core/ssr/client'

@gunnartorfis

Copy link
Copy Markdown

@schiller-manuel this breaks Clerk with Tanstack Start.
Screenshot 2025-07-17 at 09 27 31

The Clerk starter isn't working in the latest start version. The getAuth() function throws: https://github.com/TanStack/router/tree/main/examples/react/start-clerk-basic

The reason I reach out here is that I want to point the Clerk team towards something if the fix lies no their end.

@AhmedBaset

Copy link
Copy Markdown
Contributor

Is there a way to configure a custom serializer? seems like firebase' Timestamp is broken

Error reading routerStream: g [Error]: The value [object Object] of type "object" cannot be parsed/serialized.
There are few workarounds for this problem:
- Transform the value in a way that it can be serialized.
- If the reference is present on multiple runtimes (isomorphic), you can use the Reference API to map the references.
at G.parseObject (file:///path/to/seroval@1.3.2/node_modules/seroval/dist/esm/production/index.mjs:17:31059)
value: Timestamp { seconds: 1739221386, nanoseconds: 843000000 }
}
Error reading appStream: TypeError [ERR_INVALID_STATE]: Invalid state: Controller is already closed
at ReadableStreamDefaultController.enqueue (node:internal/webstreams/readablestream:1077:13)
at Object.write (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:29:18)
at Object.onData (file:///path/to/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:158:26)
at readStream (file:///home/ahmed/projects/59-haya-flower/node_modules/.pnpm/@tanstack+router-core@1.128.4/node_modules/@tanstack/router-core/dist/esm/ssr/transformStreamWithRouter.js:51:48) {
code: 'ERR_INVALID_STATE'
}
node:internal/process/promises:394
triggerUncaughtException(err, true /* fromPromise */);
^
Node.js v24.3.0

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

@AhmedBaset not yet. there will be a way to add custom seroval plugins

@AhmedBaset

Copy link
Copy Markdown
Contributor

Any fixes at the moment except downgrading?

@schiller-manuel

Copy link
Copy Markdown
CollaboratorAuthor

don't return anything from loader / beforeLoad that contains custom classes

@ttessarolo

Copy link
Copy Markdown

@schiller-manuel for instance "clerkInitialState" is a custom class (or maybe QueryClient)?
That's my context that breaks the app:

context {
queryClient: QueryClient {},
clerkInitialState: {
__internal_clerk_state: {
__clerk_ssr_state: [Object],
__publishableKey: 'pk_test_bW9yZS15ZXRpLTczLmNsZXJrLmFjY291bnRzLmRldiQ',
__proxyUrl: '',
__domain: '',
__isSatellite: false,
__signInUrl: '',
__signUpUrl: '',
__afterSignInUrl: '',
__afterSignUpUrl: '',
__clerk_debug: [Object],
__clerkJSUrl: undefined,
__clerkJSVersion: undefined,
__telemetryDisabled: false,
__telemetryDebug: false,
__signInForceRedirectUrl: '',
__signUpForceRedirectUrl: '',
__signInFallbackRedirectUrl: '',
__signUpFallbackRedirectUrl: ''
}
},
user: { id: 'user_2zrMCOP6EyuJrJoiHwIrrc5qzAp' }
}

oddsund added a commit to oddsund/router that referenced this pull request Aug 31, 2026
…dratedMatch
`DehydratedMatch['b']` is typed as `MakeRouteMatch['__beforeLoadContext']`,
an indexed-access into `RouteMatch['__beforeLoadContext']`. That field has
been tagged `@internal` since TanStack#4600 (2025-07-11); TanStack#4907 (2025-08-10) then
enabled `stripInternal` repo-wide specifically to remove `@internal`
members from the published `.d.ts`. From `router-core@1.171.16` onward
the published types no longer have `RouteMatch.__beforeLoadContext`, but
`ssr/types.ts` (moved to its current path by TanStack#6118, content otherwise
unchanged) still indexes into it, leaving a dangling reference.
This went unnoticed by plain SPA consumers for weeks because nothing in
the always-imported client path pulled `ssr/types.ts` into their type
graph. TanStack#7805's `load-client.ts` rewrite (2026-08-04) changed that: it
imports `TsrSsrGlobal` from `./ssr/types`, and `load-client.ts` is core
hydration code every consumer's `tsc` walks, SSR or not. Combined with
`skipLibCheck: false` (the TS default), that's enough to fail with:
error TS2339: Property '__beforeLoadContext' does not exist on type 'MakeRouteMatch'.
Since `__beforeLoadContext` is declared as `Record<string, unknown>` in
source, give `b` that concrete type directly instead of indexing into the
stripped member.
Verified against a built package: the emitted `dist/esm/ssr/types.d.ts`
no longer references the internal member, and a minimal consumer repro
(`skipLibCheck: false`, importing `createRouter`/`createRootRoute`) type-
checks cleanly with this dist swapped in.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants

@schiller-manuel@gunnartorfis@AhmedBaset@ttessarolo@isnifer@SeanCassiere