diff --git a/e2e/react-start/server-functions/src/routeTree.gen.ts b/e2e/react-start/server-functions/src/routeTree.gen.ts
index 6909bce9452..080480bb344 100644
--- a/e2e/react-start/server-functions/src/routeTree.gen.ts
+++ b/e2e/react-start/server-functions/src/routeTree.gen.ts
@@ -27,6 +27,7 @@ import { Route as FormdataRedirectIndexRouteImport } from './routes/formdata-red
import { Route as FactoryIndexRouteImport } from './routes/factory/index'
import { Route as CookiesIndexRouteImport } from './routes/cookies/index'
import { Route as MiddlewareSendServerFnRouteImport } from './routes/middleware/send-serverFn'
+import { Route as MiddlewareRequestMiddlewareRouteImport } from './routes/middleware/request-middleware'
import { Route as MiddlewareClientMiddlewareRouterRouteImport } from './routes/middleware/client-middleware-router'
import { Route as CookiesSetRouteImport } from './routes/cookies/set'
import { Route as FormdataRedirectTargetNameRouteImport } from './routes/formdata-redirect/target.$name'
@@ -121,6 +122,12 @@ const MiddlewareSendServerFnRoute = MiddlewareSendServerFnRouteImport.update({
path: '/middleware/send-serverFn',
getParentRoute: () => rootRouteImport,
} as any)
+const MiddlewareRequestMiddlewareRoute =
+ MiddlewareRequestMiddlewareRouteImport.update({
+ id: '/middleware/request-middleware',
+ path: '/middleware/request-middleware',
+ getParentRoute: () => rootRouteImport,
+ } as any)
const MiddlewareClientMiddlewareRouterRoute =
MiddlewareClientMiddlewareRouterRouteImport.update({
id: '/middleware/client-middleware-router',
@@ -155,6 +162,7 @@ export interface FileRoutesByFullPath {
'/submit-post-formdata': typeof SubmitPostFormdataRoute
'/cookies/set': typeof CookiesSetRoute
'/middleware/client-middleware-router': typeof MiddlewareClientMiddlewareRouterRoute
+ '/middleware/request-middleware': typeof MiddlewareRequestMiddlewareRoute
'/middleware/send-serverFn': typeof MiddlewareSendServerFnRoute
'/cookies': typeof CookiesIndexRoute
'/factory': typeof FactoryIndexRoute
@@ -178,6 +186,7 @@ export interface FileRoutesByTo {
'/submit-post-formdata': typeof SubmitPostFormdataRoute
'/cookies/set': typeof CookiesSetRoute
'/middleware/client-middleware-router': typeof MiddlewareClientMiddlewareRouterRoute
+ '/middleware/request-middleware': typeof MiddlewareRequestMiddlewareRoute
'/middleware/send-serverFn': typeof MiddlewareSendServerFnRoute
'/cookies': typeof CookiesIndexRoute
'/factory': typeof FactoryIndexRoute
@@ -202,6 +211,7 @@ export interface FileRoutesById {
'/submit-post-formdata': typeof SubmitPostFormdataRoute
'/cookies/set': typeof CookiesSetRoute
'/middleware/client-middleware-router': typeof MiddlewareClientMiddlewareRouterRoute
+ '/middleware/request-middleware': typeof MiddlewareRequestMiddlewareRoute
'/middleware/send-serverFn': typeof MiddlewareSendServerFnRoute
'/cookies/': typeof CookiesIndexRoute
'/factory/': typeof FactoryIndexRoute
@@ -227,6 +237,7 @@ export interface FileRouteTypes {
| '/submit-post-formdata'
| '/cookies/set'
| '/middleware/client-middleware-router'
+ | '/middleware/request-middleware'
| '/middleware/send-serverFn'
| '/cookies'
| '/factory'
@@ -250,6 +261,7 @@ export interface FileRouteTypes {
| '/submit-post-formdata'
| '/cookies/set'
| '/middleware/client-middleware-router'
+ | '/middleware/request-middleware'
| '/middleware/send-serverFn'
| '/cookies'
| '/factory'
@@ -273,6 +285,7 @@ export interface FileRouteTypes {
| '/submit-post-formdata'
| '/cookies/set'
| '/middleware/client-middleware-router'
+ | '/middleware/request-middleware'
| '/middleware/send-serverFn'
| '/cookies/'
| '/factory/'
@@ -297,6 +310,7 @@ export interface RootRouteChildren {
SubmitPostFormdataRoute: typeof SubmitPostFormdataRoute
CookiesSetRoute: typeof CookiesSetRoute
MiddlewareClientMiddlewareRouterRoute: typeof MiddlewareClientMiddlewareRouterRoute
+ MiddlewareRequestMiddlewareRoute: typeof MiddlewareRequestMiddlewareRoute
MiddlewareSendServerFnRoute: typeof MiddlewareSendServerFnRoute
CookiesIndexRoute: typeof CookiesIndexRoute
FactoryIndexRoute: typeof FactoryIndexRoute
@@ -433,6 +447,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof MiddlewareSendServerFnRouteImport
parentRoute: typeof rootRouteImport
}
+ '/middleware/request-middleware': {
+ id: '/middleware/request-middleware'
+ path: '/middleware/request-middleware'
+ fullPath: '/middleware/request-middleware'
+ preLoaderRoute: typeof MiddlewareRequestMiddlewareRouteImport
+ parentRoute: typeof rootRouteImport
+ }
'/middleware/client-middleware-router': {
id: '/middleware/client-middleware-router'
path: '/middleware/client-middleware-router'
@@ -473,6 +494,7 @@ const rootRouteChildren: RootRouteChildren = {
SubmitPostFormdataRoute: SubmitPostFormdataRoute,
CookiesSetRoute: CookiesSetRoute,
MiddlewareClientMiddlewareRouterRoute: MiddlewareClientMiddlewareRouterRoute,
+ MiddlewareRequestMiddlewareRoute: MiddlewareRequestMiddlewareRoute,
MiddlewareSendServerFnRoute: MiddlewareSendServerFnRoute,
CookiesIndexRoute: CookiesIndexRoute,
FactoryIndexRoute: FactoryIndexRoute,
diff --git a/e2e/react-start/server-functions/src/routes/middleware/index.tsx b/e2e/react-start/server-functions/src/routes/middleware/index.tsx
index 7af7d93343c..1119e6bfea9 100644
--- a/e2e/react-start/server-functions/src/routes/middleware/index.tsx
+++ b/e2e/react-start/server-functions/src/routes/middleware/index.tsx
@@ -24,6 +24,15 @@ function RouteComponent() {
Client Middleware can send server function reference in context
+
+
+ Request Middleware in combination with server function
+
+
)
diff --git a/e2e/react-start/server-functions/src/routes/middleware/request-middleware.tsx b/e2e/react-start/server-functions/src/routes/middleware/request-middleware.tsx
new file mode 100644
index 00000000000..58d3b6935ef
--- /dev/null
+++ b/e2e/react-start/server-functions/src/routes/middleware/request-middleware.tsx
@@ -0,0 +1,83 @@
+import { createFileRoute } from '@tanstack/react-router'
+import { createMiddleware, createServerFn } from '@tanstack/react-start'
+import { getRequest } from '@tanstack/react-start/server'
+import React from 'react'
+
+const requestMiddleware = createMiddleware({ type: 'request' }).server(
+ async ({ next, request }) => {
+ return next({
+ context: {
+ requestParam: request.url,
+ requestFunc: getRequest().url,
+ },
+ })
+ },
+)
+
+const serverFn = createServerFn()
+ .middleware([requestMiddleware])
+ .handler(async ({ context: { requestParam, requestFunc } }) => {
+ return { requestParam, requestFunc }
+ })
+
+export const Route = createFileRoute('/middleware/request-middleware')({
+ loader: () => serverFn(),
+ component: RouteComponent,
+})
+
+function RouteComponent() {
+ const loaderData = Route.useLoaderData()
+
+ const [clientData, setClientData] = React.useState(
+ null,
+ )
+
+ return (
+
+
Request Middleware in combination with server function
+
+
+
+
Loader Data
Request Param:
+
+ {loaderData.requestParam}
+
+ Request Func:
+
+ {loaderData.requestFunc}
+
+
+
+
+
+
+
+
+
Client Data
+ {clientData ? (
+
+ Request Param:
+
+ {clientData.requestParam}
+
+ Request Func:
+
+ {clientData.requestFunc}
+
+
+ ) : (
+ ' Loading ...'
+ )}
+
+
+
+ )
+}
diff --git a/e2e/react-start/server-functions/tests/server-functions.spec.ts b/e2e/react-start/server-functions/tests/server-functions.spec.ts
index 72488ad0dc1..08f48524cb8 100644
--- a/e2e/react-start/server-functions/tests/server-functions.spec.ts
+++ b/e2e/react-start/server-functions/tests/server-functions.spec.ts
@@ -382,6 +382,32 @@ test.describe('middleware', () => {
await runTest(page)
})
})
+
+ test('server function in combination with request middleware', async ({
+ page,
+ }) => {
+ await page.goto('/middleware/request-middleware')
+
+ await page.waitForLoadState('networkidle')
+
+ async function checkEqual(prefix: string) {
+ const requestParam = await page
+ .getByTestId(`${prefix}-data-request-param`)
+ .textContent()
+ expect(requestParam).not.toBe('')
+ const requestFunc = await page
+ .getByTestId(`${prefix}-data-request-func`)
+ .textContent()
+ expect(requestParam).toBe(requestFunc)
+ }
+
+ await checkEqual('loader')
+
+ await page.getByTestId('client-call-button').click()
+ await page.waitForLoadState('networkidle')
+
+ await checkEqual('client')
+ })
})
test('factory', async ({ page }) => {
diff --git a/packages/start-client-core/src/createServerFn.ts b/packages/start-client-core/src/createServerFn.ts
index 75a9a280017..bc95a6b5b9a 100644
--- a/packages/start-client-core/src/createServerFn.ts
+++ b/packages/start-client-core/src/createServerFn.ts
@@ -2,8 +2,8 @@ import { isNotFound, isRedirect } from '@tanstack/router-core'
import { mergeHeaders } from '@tanstack/router-core/ssr/client'
import { TSS_SERVER_FUNCTION_FACTORY } from './constants'
-import { getServerContextAfterGlobalMiddlewares } from './getServerContextAfterGlobalMiddlewares'
import { getStartOptions } from './getStartOptions'
+import { getStartContextServerOnly } from './getStartContextServerOnly'
import type { TSS_SERVER_FUNCTION } from './constants'
import type {
AnyValidator,
@@ -130,8 +130,9 @@ export const createServerFn: CreateServerFn = (options, __opts) => {
// The extracted function on the server-side calls
// this function
__executeServer: async (opts: any, signal: AbortSignal) => {
+ const startContext = getStartContextServerOnly()
const serverContextAfterGlobalMiddlewares =
- getServerContextAfterGlobalMiddlewares()
+ startContext.contextAfterGlobalMiddlewares
const ctx = {
...extractedFn,
...opts,
@@ -140,6 +141,7 @@ export const createServerFn: CreateServerFn = (options, __opts) => {
...opts.context,
},
signal,
+ request: startContext.request,
}
return executeMiddleware(resolvedMiddleware, 'server', ctx).then(
@@ -199,11 +201,16 @@ export async function executeMiddleware(
)
}
- const middlewareFn = (
- env === 'client' && 'client' in nextMiddleware.options
- ? nextMiddleware.options.client
- : nextMiddleware.options.server
- ) as MiddlewareFn | undefined
+ let middlewareFn: MiddlewareFn | undefined = undefined
+ if (env === 'client') {
+ if ('client' in nextMiddleware.options) {
+ middlewareFn = nextMiddleware.options.client as MiddlewareFn | undefined
+ }
+ }
+ // env === 'server'
+ else if ('server' in nextMiddleware.options) {
+ middlewareFn = nextMiddleware.options.server as MiddlewareFn | undefined
+ }
if (middlewareFn) {
// Execute the middleware
diff --git a/packages/start-client-core/src/getServerContextAfterGlobalMiddlewares.ts b/packages/start-client-core/src/getServerContextAfterGlobalMiddlewares.ts
deleted file mode 100644
index 72b740e8b3c..00000000000
--- a/packages/start-client-core/src/getServerContextAfterGlobalMiddlewares.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-import { getStartContext } from '@tanstack/start-storage-context'
-import { createServerOnlyFn } from './envOnly'
-
-export const getServerContextAfterGlobalMiddlewares = createServerOnlyFn(() => {
- const start = getStartContext()
- return start.contextAfterGlobalMiddlewares
-})
diff --git a/packages/start-client-core/src/getStartContextServerOnly.ts b/packages/start-client-core/src/getStartContextServerOnly.ts
new file mode 100644
index 00000000000..78787a49825
--- /dev/null
+++ b/packages/start-client-core/src/getStartContextServerOnly.ts
@@ -0,0 +1,4 @@
+import { getStartContext } from '@tanstack/start-storage-context'
+import { createServerOnlyFn } from './envOnly'
+
+export const getStartContextServerOnly = createServerOnlyFn(getStartContext)
diff --git a/packages/start-server-core/src/createStartHandler.ts b/packages/start-server-core/src/createStartHandler.ts
index 1589a04dc1a..ae5e5ff2afc 100644
--- a/packages/start-server-core/src/createStartHandler.ts
+++ b/packages/start-server-core/src/createStartHandler.ts
@@ -170,6 +170,7 @@ export function createStartHandler(
getRouter,
startOptions,
contextAfterGlobalMiddlewares: context,
+ request,
},
async () => {
try {
diff --git a/packages/start-storage-context/src/async-local-storage.ts b/packages/start-storage-context/src/async-local-storage.ts
index c353dbaf26d..ec02f0a47be 100644
--- a/packages/start-storage-context/src/async-local-storage.ts
+++ b/packages/start-storage-context/src/async-local-storage.ts
@@ -3,7 +3,7 @@ import type { Awaitable, RegisteredRouter } from '@tanstack/router-core'
export interface StartStorageContext {
getRouter: () => Awaitable
-
+ request: Request
// TODO type this properly
startOptions: /* AnyStartInstanceOptions*/ any