Skip to content

fix: use createServerFn().validator() instead of deprecated inputValidator#101

Merged
nicknisi merged 2 commits into
mainfrom
fix/server-fn-validator-deprecation
Jun 15, 2026
Merged

fix: use createServerFn().validator() instead of deprecated inputValidator#101
nicknisi merged 2 commits into
mainfrom
fix/server-fn-validator-deprecation

Conversation

@nicknisi

@nicknisi nicknisi commented Jun 13, 2026

Copy link
Copy Markdown
Member

Summary

Two related fixes for consumers on current TanStack Start (1.168.x+):

  1. #100 — switch all server functions/actions off the deprecated createServerFn().inputValidator() to .validator(), which TanStack now flags with a compiler warning in consumers' Vite dev.
  2. CSRF — restore CSRF protection on server-function RPC endpoints, which this SDK's required middleware pattern silently disables (details below).

1. inputValidatorvalidator (#100)

The deprecation warning consumers see:

createServerFn().inputValidator() is deprecated. Use createServerFn().validator() instead.

All 9 server-function/action call sites now use .validator().

Why this needs a dependency bump

.validator() doesn't exist in the builder until react-start 1.168.25 (which bundles start-client-core@1.170.12 + start-plugin-core@1.171.17); earlier versions only have .inputValidator(). The deprecation warning consumers see is emitted by their newer TanStack compiler transforming our shipped dist/server/*.js, so the fix has to land in source → dist, and our pinned TanStack had to move so .validator() typechecks.

⚠️ Breaking change

Raises the peer floor to @tanstack/react-start >=1.168.25. Consumers on older TanStack Start will hit .validator is not a function at runtime and must upgrade. This is the accurate floor — .validator() simply doesn't exist before it.

2. CSRF protection on server functions

TanStack Start protects server-function RPC endpoints with a default CSRF middleware — but only when an app doesn't define its own startInstance (createStartHandler injects defaultCsrfMiddleware only in the no-startInstance branch). This SDK requires consumers to register authkitMiddleware in createStart(() => ({ requestMiddleware: [...] })), which means every consumer takes over the middleware list and is silently opted out of that default — leaving server-fn endpoints unprotected from cross-site requests. That's the source of the dev warning:

TanStack Start server functions are not protected by the CSRF middleware.

The warning is accurate, and it's the SDK's own required pattern that triggers it — so we address it rather than suppress it.

  • example: add createCsrfMiddleware({ filter: (ctx) => ctx.handlerType === 'serverFn' }) to requestMiddleware, ordered before authkitMiddleware().
  • README: show it in the setup step and explain that registering authkitMiddleware makes CSRF the consumer's responsibility.

createCsrfMiddleware is a pure header check (Sec-Fetch-Site / Origin / Referer) — no token plumbing, no interaction with the AuthKit session cookie, and an isomorphic fn that no-ops on the client. The serverFn filter keeps cross-site flows like the WorkOS OAuth callback navigation working.

Changes

  • Switch all .inputValidator().validator() in actions.ts / server-functions.ts
  • Update the createServerFn mocks in the test suite to match (4 spots)
  • Bump @tanstack/react-start ^1.168.25, react-router ^1.170.15, start-server-core ^1.169.14 (root + example)
  • Raise peerDependencies["@tanstack/react-start"] to >=1.168.25
  • Add createCsrfMiddleware to the example's start.ts + document it in the README
  • Remove the example's TanStackRouterDevtools panel (see note below)

Note: example devtools removed (unrelated upstream bug)

The router bump pulls @tanstack/router-core@1.171.13, which removed routerState.cachedMatches. Every available @tanstack/router-devtools-core (≤1.168.0) still reads that field, so <TanStackRouterDevtools> crashes with cachedMatches is not iterable (client console only — the app works). No devtools version is currently compatible with this router-core (TanStack's own start-workos example is broken the same way). The panel is removed from the example with a comment; the dependency is kept so it can be re-enabled in a 2-line uncomment once upstream catches up.

Verification

  • pnpm typecheck
  • pnpm build ✓ — shipped dist emits .validator(), zero inputValidator
  • pnpm test ✓ — 222/222
  • cd example && pnpm typecheck && pnpm build ✓ — no deprecation/leak warnings; createCsrfMiddleware import + ctx.handlerType typecheck clean
  • pnpm run build:check (bundle-leak guard) ✓ — no server fingerprints in client bundle
  • pnpm lint / pnpm format:check
  • Confirmed the consumer compiler still rewrites our dist to RPC (.validator(...).handler(createSsrRpc(...)))
  • Confirmed CSRF fix at runtime — a fresh dev server's first server-fn RPC request no longer emits the "not protected by the CSRF middleware" warning

Closes #100

…dator

TanStack Start deprecated createServerFn().inputValidator() in favor of
.validator(); the alias emits a compiler warning in consumers' Vite dev.
Switch all server functions and actions to .validator().

.validator() only exists from react-start 1.168.25 (start-client-core
1.170.12 / start-plugin-core 1.171.17), so bump the dev deps and raise
the peer floor to match.

- Switch 9 inputValidator call sites in actions.ts / server-functions.ts
- Update createServerFn mocks across the test suite to match
- Bump @tanstack/react-start ^1.168.25, react-router ^1.170.15,
  start-server-core ^1.169.14 (root + example)
- Raise peerDependencies @tanstack/react-start to >=1.168.25
- Drop the example's TanStackRouterDevtools panel: the bumped
  router-core@1.171.13 removed routerState.cachedMatches, which all
  current router-devtools-core versions still read (crashes the panel)

BREAKING CHANGE: requires @tanstack/react-start >=1.168.25, where
createServerFn().validator() exists. Consumers on older TanStack Start
versions must upgrade.

Closes #100

@devin-ai-integration devin-ai-integration Bot left a comment

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.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no bugs or issues to report.

Open in Devin Review

@greptile-apps

greptile-apps Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR migrates all 9 createServerFn().inputValidator() call sites in actions.ts and server-functions.ts to the non-deprecated .validator() API introduced in @tanstack/react-start@1.168.25, and updates the corresponding test mocks across four spec files to match.

  • Core migration: All .inputValidator(fn) chains replaced with .validator(fn) using identical passthrough validator functions — no behavioural change, only API surface change. Peer dependency floor for @tanstack/react-start correctly raised to >=1.168.25.
  • Security improvement: The example app and README both gain createCsrfMiddleware scoped to serverFn requests, restoring the CSRF protection that defining a custom startInstance silently opts consumers out of.
  • Example devtools: TanStackRouterDevtools is temporarily commented out with a clear explanation of the upstream router-core/devtools-core incompatibility; the dependency is retained for easy re-enablement.

Confidence Score: 5/5

Safe to merge — the change is a straightforward API rename with no logic changes to authentication or session handling.

All 9 validator call sites are updated consistently, the test mocks across three spec files are aligned with the new builder shape, and the typecheck + full test suite have passed. The peer dep bump is accurate and well-documented. The only minor gap is that the @tanstack/react-router peer floor was not raised in sync with react-start, but this does not affect the correctness of the library itself.

package.json — the @tanstack/react-router peer dep minimum could be tightened to match the implicit floor imposed by @tanstack/react-start@1.168.25.

Important Files Changed

Filename Overview
src/server/actions.ts All .inputValidator() calls replaced with .validator() using identity passthrough functions; no logic changes.
src/server/server-functions.ts Same .inputValidator() → .validator() migration; all 5 call sites updated consistently.
src/server/actions.spec.ts createServerFn mock updated to expose .validator() builder method instead of .inputValidator(); all existing test cases pass through.
src/server/server-functions.spec.ts createServerFn mock updated to match new .validator() API; test coverage unchanged.
tests/integration.spec.ts Integration test mock updated to .validator(); tests only verify module structure so minimal mock is sufficient.
package.json peerDependencies["@tanstack/react-start"] raised to >=1.168.25; @tanstack/react-router peer floor left at >=1.0.0 despite the new react-start minimum implicitly requiring ~1.170.
example/src/start.ts createCsrfMiddleware added before authkitMiddleware with serverFn-scoped filter; restores the CSRF protection opted out by defining a custom startInstance.
example/src/routes/__root.tsx TanStackRouterDevtools removed with explanatory comment citing the router-core/devtools-core incompatibility; clean temporary workaround.
README.md CSRF guidance added to setup instructions and authkitMiddleware reference; accurate and helpful for consumers who would otherwise silently lose default CSRF protection.

Sequence Diagram

sequenceDiagram
    participant Client
    participant TanStack Start Runtime
    participant csrfMiddleware
    participant authkitMiddleware
    participant ServerFn as Server Function (.validator().handler())

    Client->>TanStack Start Runtime: HTTP request (serverFn RPC)
    TanStack Start Runtime->>csrfMiddleware: filter(ctx.handlerType === 'serverFn')
    alt Cross-site request
        csrfMiddleware-->>Client: 403 Forbidden
    else Same-site request
        csrfMiddleware->>authkitMiddleware: next()
        authkitMiddleware->>authkitMiddleware: resolve session / set auth context
        authkitMiddleware->>ServerFn: next()
        ServerFn->>ServerFn: .validator(fn) — validate/pass-through input
        ServerFn->>ServerFn: .handler(fn) — execute business logic
        ServerFn-->>Client: response
    end
Loading

Reviews (2): Last reviewed commit: "fix: protect server functions with CSRF ..." | Re-trigger Greptile

Defining a startInstance with a custom requestMiddleware list opts an app
out of the CSRF middleware TanStack Start applies to server functions by
default (createStartHandler only injects defaultCsrfMiddleware when no
startInstance exists). Because this SDK requires consumers to register
authkitMiddleware in requestMiddleware, every consumer was silently opted
out, leaving server-fn RPC endpoints unprotected from cross-site requests
(this is the "server functions are not protected by the CSRF middleware"
dev warning).

- example/src/start.ts: add createCsrfMiddleware (filtered to serverFn,
  ordered before authkitMiddleware) to restore the protection
- README: show createCsrfMiddleware in the setup step and explain why the
  startInstance opt-out makes it the consumer's responsibility

createCsrfMiddleware is a pure header check (Sec-Fetch-Site / Origin /
Referer) with no token plumbing and no interaction with the AuthKit
session cookie; it's an isomorphic fn that no-ops on the client.

Verified: example typecheck + build clean, bundle-leak guard clean, and a
fresh dev server's first server-fn RPC request no longer emits the warning.
@nicknisi nicknisi requested a review from gjtorikian June 15, 2026 18:11
@nicknisi nicknisi merged commit f74fb28 into main Jun 15, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

createServerFn().inputValidator() deprecation warning with TanStack Start

2 participants