Agent Skills: tRPC v11 Knowledge Patch

>

UncategorizedID: nevaberry/nevaberry-plugins/trpc-knowledge-patch

Install this agent skill to your local

pnpm dlx add-skill https://github.com/Nevaberry/nevaberry-plugins/tree/HEAD/plugins/trpc-knowledge-patch/skills/trpc-knowledge-patch

Skill Files

Browse the full folder contents for trpc-knowledge-patch.

Download Skill

Loading file tree…

plugins/trpc-knowledge-patch/skills/trpc-knowledge-patch/SKILL.md

Skill Metadata

Name
trpc-knowledge-patch
Description
>

tRPC v11 Knowledge Patch

Claude's baseline knowledge covers tRPC through v10. This skill provides features from v11 (December 2024) onwards.

Reference Index

  • v11 Migration & Breaking Changes — Transformers moved to links, React Query v5 required, createTRPCProxyClient renamed, TypeScript 5.7.2+ / Node 18+ requirements
  • Subscriptions & Streaming — SSE subscriptions via async generators, tracked() reconnection, httpSubscriptionLink, useSubscription status union, streaming queries/mutations, embedded promises with httpBatchStreamLink
  • TanStack React Query Integration — New @trpc/tanstack-react-query package, createTRPCContext, createTRPCOptionsProxy for RSC/singletons, .queryOptions()/.mutationOptions() API, migration codemod
  • Next.js Server Actionsexperimental_caller with experimental_nextAppDirCaller, turning procedures into plain async functions, auth guards, progressive enhancement
  • Advanced Features — Lazy routers, localLink, shorthand router definitions, non-JSON content types (FormData/File/Blob), @trpc/openapi (alpha), HTTP/2 standalone adapter

Quick Reference — v11 Breaking Changes

| Change | v10 | v11 | |--------|-----|-----| | Transformer location | createTRPCClient({ transformer }) | httpBatchLink({ transformer }) | | React Query version | v4 | v5 required (isPending replaces isLoading) | | Client constructor | createTRPCProxyClient | createTRPCClient (same API) | | Subscriptions | Observable + WebSocket | Async generator + SSE | | Min TypeScript | — | >=5.7.2 | | Min Node.js | — | 18+ |

Quick Reference — Essential Patterns

Transformer in link (v11)

import { httpBatchLink } from '@trpc/client';
import superjson from 'superjson';

httpBatchLink({
  url: '/api/trpc',
  transformer: superjson, // moved here from createTRPCClient
});

SSE subscription (async generator)

const appRouter = router({
  onEvent: publicProcedure.subscription(async function* (opts) {
    for await (const data of on(ee, 'event', { signal: opts.signal })) {
      yield data[0];
    }
  }),
});

SSE config in initTRPC.create():

const t = initTRPC.create({
  sse: {
    ping: { enabled: true, intervalMs: 15_000 },
    client: { reconnectAfterInactivityMs: 20_000 },
  },
});

tracked() — subscription reconnection

import { tracked } from '@trpc/server';

t.procedure
  .input(z.object({ lastEventId: z.string().nullish() }).optional())
  .subscription(async function* (opts) {
    if (opts.input?.lastEventId) { /* fetch missed events */ }
    for await (const [data] of on(ee, 'add', { signal: opts.signal })) {
      yield tracked(data.id, data); // client tracks this id
    }
  });

httpSubscriptionLink setup

import { splitLink, httpBatchLink, httpSubscriptionLink } from '@trpc/client';

const client = createTRPCClient<AppRouter>({
  links: [
    splitLink({
      condition: (op) => op.type === 'subscription',
      true: httpSubscriptionLink({
        url: '/api/trpc',
        eventSourceOptions: async ({ op }) => ({
          headers: { authorization: `Bearer ${token}` },
        }),
      }),
      false: httpBatchLink({ url: '/api/trpc' }),
    }),
  ],
});

useSubscription return type

Returns discriminated union on status: 'idle' | 'connecting' | 'pending' | 'error'.

const sub = trpc.onEvent.useSubscription(undefined, {
  onData: (data) => {},
  onError: (err) => {},
});
// sub.status, sub.data, sub.error, sub.reset()

Streaming query (httpBatchStreamLink)

const appRouter = router({
  stream: publicProcedure.query(async function* () {
    for (let i = 0; i < 10; i++) {
      yield i;
      await new Promise((r) => setTimeout(r, 500));
    }
  }),
});
// Client: for await (const v of await trpc.stream.query()) { ... }

Embedded promises in streamed responses

publicProcedure.query(() => ({
  instant: 'ready',
  slow: slowAsyncFn(), // streams when resolved
}));

TanStack React Query options API

import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import { useTRPC } from './trpc';

function MyComponent() {
  const trpc = useTRPC();
  const greeting = useQuery(trpc.greeting.queryOptions({ name: 'Jerry' }));
  const create = useMutation(trpc.createUser.mutationOptions());
  // Invalidation
  const qc = useQueryClient();
  await qc.invalidateQueries(trpc.greeting.queryFilter({ name: 'Jerry' }));
}

createTRPCOptionsProxy (RSC / singletons)

import { createTRPCOptionsProxy } from '@trpc/tanstack-react-query';
// RSC: direct router call, no HTTP
const trpc = createTRPCOptionsProxy({ ctx: createTRPCContext, router: appRouter, queryClient: getQueryClient });
// SPA singleton:
const trpc = createTRPCOptionsProxy<AppRouter>({ client: trpcClient, queryClient });
void queryClient.prefetchQuery(trpc.hello.queryOptions({ text: 'world' }));

Migration codemod: npx @trpc/upgrade (select "Migrate Hooks to xxxOptions API").

Next.js server action

'use server';
import { protectedAction } from '../server/trpc';
import { z } from 'zod';

export const createPost = protectedAction
  .meta({ span: 'create-post' })
  .input(z.object({ title: z.string() }))
  .mutation(async (opts) => { /* opts.ctx.user, opts.input.title */ });
// createPost is now: (input: { title: string }) => Promise<void>

Lazy router

import { lazy } from '@trpc/server';

const appRouter = router({
  greeting: lazy(() => import('./greeting.js')),
  user: lazy(() => import('./user.js').then((m) => m.userRouter)),
});

Non-JSON with batch link (splitLink)

import { splitLink, httpBatchLink, httpLink, isNonJsonSerializable } from '@trpc/client';

createTRPCClient<AppRouter>({
  links: [
    splitLink({
      condition: (op) => isNonJsonSerializable(op.input),
      true: httpLink({ url }),
      false: httpBatchLink({ url }),
    }),
  ],
});

@trpc/openapi — generate OpenAPI spec

pnpm add @trpc/openapi
pnpm exec trpc-openapi ./src/server/router.ts -o api.json --title "My API" --version 1.0.0
tRPC v11 Knowledge Patch Skill | Agent Skills