Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { createMiddleware, createServerFn } from '@tanstack/react-start'
import { getRequest } from '@tanstack/react-start/server'

const fooMiddleware = createMiddleware({ type: 'function' }).server(
({ next }) => {
const request = getRequest()
console.log('Foo middleware triggered')
return next({
context: { foo: 'foo' } as const,
context: { foo: 'foo', method: request.method } as const,
})
},
)

export const createFooServerFn = createServerFn().middleware([fooMiddleware])

export const fooFnInsideFactoryFile = createFooServerFn().handler(
async ({ context, method }) => {
console.log('fooFnInsideFactoryFile handler triggered', method)
async ({ context }) => {
console.log('fooFnInsideFactoryFile handler triggered', context.method)
return {
name: 'fooFnInsideFactoryFile',
context,
Expand Down
34 changes: 26 additions & 8 deletions e2e/react-start/server-functions/src/routes/factory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const functions = {

expected: {
name: 'fooFnInsideFactoryFile',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'GET' },
},
},
fooFn: {
Expand All @@ -48,7 +48,7 @@ const functions = {

expected: {
name: 'fooFn',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'GET' },
},
},
fooFnPOST: {
Expand All @@ -57,7 +57,7 @@ const functions = {

expected: {
name: 'fooFnPOST',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'POST' },
},
},
barFn: {
Expand All @@ -66,7 +66,7 @@ const functions = {

expected: {
name: 'barFn',
context: { foo: 'foo', bar: 'bar' },
context: { foo: 'foo', method: 'GET', bar: 'bar' },
},
},
barFnPOST: {
Expand All @@ -75,7 +75,7 @@ const functions = {

expected: {
name: 'barFnPOST',
context: { foo: 'foo', bar: 'bar' },
context: { foo: 'foo', method: 'POST', bar: 'bar' },
},
},
localFn: {
Expand All @@ -84,7 +84,13 @@ const functions = {

expected: {
name: 'localFn',
context: { foo: 'foo', bar: 'bar', local: 'local', another: 'another' },
context: {
foo: 'foo',
method: 'GET',
bar: 'bar',
local: 'local',
another: 'another',
},
},
},
localFnPOST: {
Expand All @@ -93,15 +99,27 @@ const functions = {

expected: {
name: 'localFnPOST',
context: { foo: 'foo', bar: 'bar', local: 'local', another: 'another' },
context: {
foo: 'foo',
method: 'POST',
bar: 'bar',
local: 'local',
another: 'another',
},
},
},
composedFn: {
fn: composedFn,
type: 'serverFn',
expected: {
name: 'composedFn',
context: { foo: 'foo', bar: 'bar', another: 'another', local: 'local' },
context: {
foo: 'foo',
method: 'GET',
bar: 'bar',
another: 'another',
local: 'local',
},
},
},
fakeFn: {
Expand Down
15 changes: 9 additions & 6 deletions e2e/solid-start/basic-cloudflare/worker-configuration.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@
// Generated by Wrangler by running `wrangler types` (hash: b11df627d8b3c51b1bf3230a546b0f20)
// Runtime types generated with workerd@1.20251118.0 2025-09-24 nodejs_compat
declare namespace Cloudflare {
interface Env {
MY_VAR: "Hello from Cloudflare";
}
interface Env {
MY_VAR: 'Hello from Cloudflare'
}
}
interface Env extends Cloudflare.Env {}
type StringifyValues<EnvType extends Record<string, unknown>> = {
[Binding in keyof EnvType]: EnvType[Binding] extends string ? EnvType[Binding] : string;
};
[Binding in keyof EnvType]: EnvType[Binding] extends string
? EnvType[Binding]
: string
}
declare namespace NodeJS {
interface ProcessEnv extends StringifyValues<Pick<Cloudflare.Env, "MY_VAR">> {}
interface ProcessEnv
extends StringifyValues<Pick<Cloudflare.Env, 'MY_VAR'>> {}
}

// Begin runtime types
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { createMiddleware, createServerFn } from '@tanstack/solid-start'
import { getRequest } from '@tanstack/solid-start/server'

const fooMiddleware = createMiddleware({ type: 'function' }).server(
({ next }) => {
const request = getRequest()
console.log('Foo middleware triggered')
return next({
context: { foo: 'foo' } as const,
context: { foo: 'foo', method: request.method } as const,
})
},
)

export const createFooServerFn = createServerFn().middleware([fooMiddleware])

export const fooFnInsideFactoryFile = createFooServerFn().handler(
async ({ context, method }) => {
console.log('fooFnInsideFactoryFile handler triggered', method)
async ({ context }) => {
console.log('fooFnInsideFactoryFile handler triggered', context.method)
return {
name: 'fooFnInsideFactoryFile',
context,
Expand Down
34 changes: 26 additions & 8 deletions e2e/solid-start/server-functions/src/routes/factory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ const functions = {

expected: {
name: 'fooFnInsideFactoryFile',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'GET' },
},
},
fooFn: {
Expand All @@ -48,7 +48,7 @@ const functions = {

expected: {
name: 'fooFn',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'GET' },
},
},
fooFnPOST: {
Expand All @@ -57,7 +57,7 @@ const functions = {

expected: {
name: 'fooFnPOST',
context: { foo: 'foo' },
context: { foo: 'foo', method: 'POST' },
},
},
barFn: {
Expand All @@ -66,7 +66,7 @@ const functions = {

expected: {
name: 'barFn',
context: { foo: 'foo', bar: 'bar' },
context: { foo: 'foo', method: 'GET', bar: 'bar' },
},
},
barFnPOST: {
Expand All @@ -75,7 +75,7 @@ const functions = {

expected: {
name: 'barFnPOST',
context: { foo: 'foo', bar: 'bar' },
context: { foo: 'foo', method: 'POST', bar: 'bar' },
},
},
localFn: {
Expand All @@ -84,7 +84,13 @@ const functions = {

expected: {
name: 'localFn',
context: { foo: 'foo', bar: 'bar', local: 'local', another: 'another' },
context: {
foo: 'foo',
method: 'GET',
bar: 'bar',
local: 'local',
another: 'another',
},
},
},
localFnPOST: {
Expand All @@ -93,15 +99,27 @@ const functions = {

expected: {
name: 'localFnPOST',
context: { foo: 'foo', bar: 'bar', local: 'local', another: 'another' },
context: {
foo: 'foo',
method: 'POST',
bar: 'bar',
local: 'local',
another: 'another',
},
},
},
composedFn: {
fn: composedFn,
type: 'serverFn',
expected: {
name: 'composedFn',
context: { foo: 'foo', bar: 'bar', another: 'another', local: 'local' },
context: {
foo: 'foo',
method: 'GET',
bar: 'bar',
another: 'another',
local: 'local',
},
},
},
fakeFn: {
Expand Down
20 changes: 6 additions & 14 deletions packages/start-client-core/src/createServerFn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -158,13 +158,11 @@ export const createServerFn: CreateServerFn<Register> = (options, __opts) => {
},
} as ServerFnBuilder<Register, Method>
const fun = (options?: { method?: Method }) => {
return {
...res,
options: {
...res.options,
...options,
},
const newOptions = {
...resolvedOptions,
...options,
}
return createServerFn(undefined, newOptions) as any
}
return Object.assign(fun, res) as any
}
Expand Down Expand Up @@ -314,16 +312,10 @@ export type ServerFn<
TInputValidator,
TResponse,
> = (
ctx: ServerFnCtx<TRegister, TMethod, TMiddlewares, TInputValidator>,
ctx: ServerFnCtx<TRegister, TMiddlewares, TInputValidator>,
) => ServerFnReturnType<TRegister, TResponse>

export interface ServerFnCtx<
TRegister,
TMethod,
TMiddlewares,
TInputValidator,
> {
method: TMethod
export interface ServerFnCtx<TRegister, TMiddlewares, TInputValidator> {
data: Expand<IntersectAllValidatorOutputs<TMiddlewares, TInputValidator>>
context: Expand<AssignAllServerFnContext<TRegister, TMiddlewares, {}>>
signal: AbortSignal
Expand Down
17 changes: 0 additions & 17 deletions packages/start-client-core/src/tests/createServerFn.test-d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,13 @@ import type {
} from '@tanstack/router-core'
import type { ConstrainValidator, ServerFnReturnType } from '../createServerFn'

test('createServerFn method with autocomplete', () => {
createServerFn().handler((options) => {
expectTypeOf(options.method).toEqualTypeOf<'GET' | 'POST'>()
})
})

test('createServerFn without middleware', () => {
expectTypeOf(createServerFn()).toHaveProperty('handler')
expectTypeOf(createServerFn()).toHaveProperty('middleware')
expectTypeOf(createServerFn()).toHaveProperty('inputValidator')

createServerFn({ method: 'GET' }).handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: undefined
signal: AbortSignal
Expand All @@ -45,7 +38,6 @@ test('createServerFn with validator', () => {

const fn = fnAfterValidator.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: {
a: string
Expand Down Expand Up @@ -105,7 +97,6 @@ test('createServerFn with middleware and context', () => {

fnWithMiddleware.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: {
readonly a: 'a'
readonly b: 'b'
Expand Down Expand Up @@ -149,7 +140,6 @@ describe('createServerFn with middleware and validator', () => {
)
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: {
readonly outputA: 'outputA'
Expand Down Expand Up @@ -250,7 +240,6 @@ test('createServerFn where validator is a primitive', () => {
.inputValidator(() => 'c' as const)
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: 'c'
signal: AbortSignal
Expand All @@ -263,7 +252,6 @@ test('createServerFn where validator is optional if object is optional', () => {
.inputValidator((input: 'c' | undefined) => input)
.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: 'c' | undefined
signal: AbortSignal
Expand All @@ -285,7 +273,6 @@ test('createServerFn where validator is optional if object is optional', () => {
test('createServerFn where data is optional if there is no validator', () => {
const fn = createServerFn({ method: 'GET' }).handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: undefined
data: undefined
signal: AbortSignal
Expand Down Expand Up @@ -475,7 +462,6 @@ test('incrementally building createServerFn with multiple middleware calls', ()

builderWithMw1.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: {
readonly a: 'a'
}
Expand All @@ -495,7 +481,6 @@ test('incrementally building createServerFn with multiple middleware calls', ()

builderWithMw2.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'POST'
context: {
readonly a: 'a'
readonly b: 'b'
Expand All @@ -516,7 +501,6 @@ test('incrementally building createServerFn with multiple middleware calls', ()

builderWithMw3.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: {
readonly a: 'a'
readonly b: 'b'
Expand Down Expand Up @@ -550,7 +534,6 @@ test('compose middlewares and server function factories', () => {

composedBuilder.handler((options) => {
expectTypeOf(options).toEqualTypeOf<{
method: 'GET'
context: {
readonly a: 'a'
readonly b: 'b'
Expand Down
Loading