agentsclimarketplace

Start middleware

Skill fusengine/agents/plugins/tanstack-start-expert/skills/start-middleware

Use when composing cross-cutting server logic in TanStack Start with createMiddleware — request vs server function middleware, chaining via .middleware([...]), shared context with next({ context }), client↔server sendContext, client middleware (.client), global middleware via createStart in src/start.ts, middleware factories for authorization, and staticFunctionMiddleware. Do NOT use for: defining the RPC itself (use start-server-functions), raw HTTP endpoints (use start-server-routes), or route-level UX guards (use router beforeLoad).From its SKILL.md

Install
npx -y skills add fusengine/agents --skill start-middleware

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 22 stars22 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

5.1 KB, 974 tokens by cl100k_base, as published. Nobody here has run it

TanStack Start Middleware

Middleware customizes the behavior of server functions and server routes. It is composable — one middleware can depend on others to form an ordered chain. Import createMiddleware from @tanstack/react-start. This skill targets @tanstack/react-start v1.166.2.

Agent Workflow (MANDATORY)

Before implementing, verify current APIs against Context7 (/websites/tanstack_start_framework_react) + Exa, then explore the target codebase. After changes, run fuse-ai-pilot:sniper.

Critical Rules (read first)

  1. TypeScript enforces method order: .middleware() → .validator() → .client() → .server(). Any other order is a type error.
  2. Shape validation is NOT authorization. A parsed UUID from sendContext is a well-formed identifier, not an authorized one. Always re-check access against the session principal before using a client-sent value as a query key, filter, or path param.
  3. Client context is not sent to the server by default. You must opt in with next({ sendContext }). Anything the client sends, the client can lie about — derive the session from a server-trusted source (cookie + DB), never from sendContext.
  4. .client() runs on the server during SSR. Guard browser-only APIs (localStorage, window) with typeof window !== 'undefined'.
  5. staticFunctionMiddleware must be LAST in the chain (from @tanstack/start-static-server-functions, experimental).

Overview

FeatureRequest MiddlewareServer Function Middleware
Created withcreateMiddleware()createMiddleware({ type: 'function' })
ScopeAll server requests (SSR, routes, functions)Server functions only
Methods.server().client(), .server()
Input validationNoYes (.validator())
Client-side logicNoYes

Request middleware cannot depend on server function middleware; server function middleware can depend on both.

Architecture

src/
├── start.ts              # createStart → global request/function middleware
├── middleware/
│   ├── auth.ts           # authMiddleware (request) + authorization factory
│   └── logging.ts        # request logging

→ See auth-authorization.md

Reference Guide

Concepts

TopicReferenceLoad when
Types & chainingtypes.mdChoosing request vs function middleware, attaching to fns/routes
Context passingcontext.mdSharing data via next(), sendContext client↔server, headers/fetch
Global & staticglobal.mdGlobal middleware, execution order, staticFunctionMiddleware

Templates

TemplateWhen to Use
auth-authorization.mdAuth + permission-based authorization factory
client-middleware.mdClient-side headers, custom fetch, telemetry

Quick Reference

Request middleware

import { createMiddleware } from '@tanstack/react-start'

const logging = createMiddleware().server(async ({ next, request }) => {
  console.log(request.url)
  return next()
})

Server function middleware with context

const auth = createMiddleware().server(async ({ next, request }) => {
  const session = await getSession(request.headers)
  if (!session) throw new Error('Unauthorized')
  return next({ context: { session } }) // typed downstream
})

const fn = createServerFn().middleware([auth]).handler(async ({ context }) =>
  db.orders.findMany({ where: { userId: context.session.userId } }),
)

→ See context.md for sendContext and header merging

Best Practices

DO

  • Load the session in a request middleware from a server-trusted cookie
  • Re-check access (membership/role) before trusting any client-sent id
  • Use a factory for parameterized authorization (permissions per function)
  • Keep method chains in the enforced order

DON'T

  • Trust sendContext shape as authorization
  • Call localStorage/window in .client() without an SSR guard
  • Place staticFunctionMiddleware anywhere but last

What ships with it: 6 files

16.1 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.