@trpc/server 11.14.0 → 11.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@trpc/server",
3
3
  "type": "module",
4
4
  "sideEffects": false,
5
- "version": "11.14.0",
5
+ "version": "11.14.1",
6
6
  "description": "The tRPC server library",
7
7
  "author": "KATT",
8
8
  "license": "MIT",
@@ -187,7 +187,10 @@
187
187
  "shared",
188
188
  "unstable-core-do-not-import",
189
189
  "!**/*.test.*",
190
- "!**/__tests__"
190
+ "!**/__tests__",
191
+ "skills",
192
+ "!skills/_artifacts",
193
+ "bin"
191
194
  ],
192
195
  "publishConfig": {
193
196
  "access": "public"
@@ -195,6 +198,7 @@
195
198
  "devDependencies": {
196
199
  "@fastify/websocket": "^11.0.0",
197
200
  "@oxc-project/runtime": "0.115.0",
201
+ "@tanstack/intent": "^0.0.20",
198
202
  "@tanstack/react-query": "^5.80.3",
199
203
  "@types/aws-lambda": "^8.10.149",
200
204
  "@types/express": "^5.0.0",
@@ -228,5 +232,11 @@
228
232
  "peerDependencies": {
229
233
  "typescript": ">=5.7.2"
230
234
  },
231
- "gitHead": "6e03f5c2f8d8ebaa237747d2db447737393402c6"
235
+ "keywords": [
236
+ "tanstack-intent"
237
+ ],
238
+ "bin": {
239
+ "intent": "./bin/intent.js"
240
+ },
241
+ "gitHead": "e896259af491fc4b1c9e8fc320817e2222bae869"
232
242
  }
@@ -0,0 +1,188 @@
1
+ ---
2
+ name: adapter-aws-lambda
3
+ description: >
4
+ Deploy tRPC on AWS Lambda with awsLambdaRequestHandler() from
5
+ @trpc/server/adapters/aws-lambda for API Gateway v1 (REST, APIGatewayProxyEvent)
6
+ and v2 (HTTP, APIGatewayProxyEventV2), and Lambda Function URLs. Enable response
7
+ streaming with awsLambdaStreamingRequestHandler() wrapped in
8
+ awslambda.streamifyResponse(). CreateAWSLambdaContextOptions provides event and
9
+ context for context creation.
10
+ type: core
11
+ library: trpc
12
+ library_version: '11.14.0'
13
+ requires:
14
+ - server-setup
15
+ sources:
16
+ - www/docs/server/adapters/aws-lambda.md
17
+ - examples/lambda-url/
18
+ - examples/lambda-api-gateway/
19
+ ---
20
+
21
+ # tRPC — Adapter: AWS Lambda
22
+
23
+ ## Setup
24
+
25
+ ```ts
26
+ // server.ts
27
+ import { initTRPC } from '@trpc/server';
28
+ import type { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
29
+ import { awsLambdaRequestHandler } from '@trpc/server/adapters/aws-lambda';
30
+ import type { APIGatewayProxyEventV2 } from 'aws-lambda';
31
+ import { z } from 'zod';
32
+
33
+ const t = initTRPC.create();
34
+
35
+ const appRouter = t.router({
36
+ greet: t.procedure
37
+ .input(z.object({ name: z.string() }))
38
+ .query(({ input }) => ({ greeting: `Hello, ${input.name}!` })),
39
+ });
40
+
41
+ export type AppRouter = typeof appRouter;
42
+
43
+ const createContext = ({
44
+ event,
45
+ context,
46
+ }: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({
47
+ event,
48
+ lambdaContext: context,
49
+ });
50
+
51
+ export const handler = awsLambdaRequestHandler({
52
+ router: appRouter,
53
+ createContext,
54
+ });
55
+ ```
56
+
57
+ ## Core Patterns
58
+
59
+ ### API Gateway v1 (REST) handler
60
+
61
+ ```ts
62
+ import type { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
63
+ import { awsLambdaRequestHandler } from '@trpc/server/adapters/aws-lambda';
64
+ import type { APIGatewayProxyEvent } from 'aws-lambda';
65
+ import { appRouter } from './router';
66
+
67
+ const createContext = ({
68
+ event,
69
+ context,
70
+ }: CreateAWSLambdaContextOptions<APIGatewayProxyEvent>) => ({
71
+ user: event.requestContext.authorizer?.claims,
72
+ });
73
+
74
+ export const handler = awsLambdaRequestHandler({
75
+ router: appRouter,
76
+ createContext,
77
+ });
78
+ ```
79
+
80
+ Use `APIGatewayProxyEvent` for REST API (v1 payload format) and `APIGatewayProxyEventV2` for HTTP API (v2 payload format).
81
+
82
+ ### Response streaming with awsLambdaStreamingRequestHandler
83
+
84
+ ```ts
85
+ /// <reference types="aws-lambda" />
86
+ import type { CreateAWSLambdaContextOptions } from '@trpc/server/adapters/aws-lambda';
87
+ import { awsLambdaStreamingRequestHandler } from '@trpc/server/adapters/aws-lambda';
88
+ import type { APIGatewayProxyEventV2 } from 'aws-lambda';
89
+ import { appRouter } from './router';
90
+
91
+ const createContext = ({
92
+ event,
93
+ context,
94
+ }: CreateAWSLambdaContextOptions<APIGatewayProxyEventV2>) => ({});
95
+
96
+ export const handler = awslambda.streamifyResponse(
97
+ awsLambdaStreamingRequestHandler({
98
+ router: appRouter,
99
+ createContext,
100
+ }),
101
+ );
102
+ ```
103
+
104
+ Response streaming is supported for Lambda Function URLs and API Gateway REST APIs (with `responseTransferMode: STREAM`). The `awslambda` namespace is provided by the Lambda execution environment.
105
+
106
+ ### Streaming async generator procedure
107
+
108
+ ```ts
109
+ import { initTRPC } from '@trpc/server';
110
+
111
+ const t = initTRPC.create();
112
+
113
+ export const appRouter = t.router({
114
+ countdown: t.procedure.query(async function* () {
115
+ for (let i = 10; i >= 0; i--) {
116
+ await new Promise((resolve) => setTimeout(resolve, 500));
117
+ yield i;
118
+ }
119
+ }),
120
+ });
121
+ ```
122
+
123
+ Pair with `httpBatchStreamLink` on the client for streamed responses.
124
+
125
+ ## Common Mistakes
126
+
127
+ ### HIGH Using httpBatchLink with per-procedure API Gateway resources
128
+
129
+ Wrong:
130
+
131
+ ```ts
132
+ // API Gateway has a separate resource for each procedure
133
+ // e.g., /getUser, /createUser
134
+ // Client uses:
135
+ import { httpBatchLink } from '@trpc/client';
136
+
137
+ httpBatchLink({ url: 'https://api.example.com' });
138
+ // Batch request to /getUser,createUser → 404
139
+ ```
140
+
141
+ Correct:
142
+
143
+ ```ts
144
+ import { httpBatchLink, httpLink } from '@trpc/client';
145
+
146
+ // Option A: Single catch-all resource (e.g., /{proxy+})
147
+ httpBatchLink({ url: 'https://api.example.com' });
148
+
149
+ // Option B: Per-procedure resources with httpLink (no batching)
150
+ httpLink({ url: 'https://api.example.com' });
151
+ ```
152
+
153
+ `httpBatchLink` sends multiple procedure names in the URL path (e.g., `getUser,createUser`). If API Gateway routes are per-procedure, the combined path does not match any resource and returns 404. Use a single catch-all resource or switch to `httpLink`.
154
+
155
+ Source: www/docs/server/adapters/aws-lambda.md
156
+
157
+ ### HIGH Forgetting streamifyResponse wrapper for streaming
158
+
159
+ Wrong:
160
+
161
+ ```ts
162
+ export const handler = awsLambdaStreamingRequestHandler({
163
+ router: appRouter,
164
+ createContext,
165
+ });
166
+ ```
167
+
168
+ Correct:
169
+
170
+ ```ts
171
+ export const handler = awslambda.streamifyResponse(
172
+ awsLambdaStreamingRequestHandler({
173
+ router: appRouter,
174
+ createContext,
175
+ }),
176
+ );
177
+ ```
178
+
179
+ `awsLambdaStreamingRequestHandler` requires wrapping with `awslambda.streamifyResponse()` to enable Lambda response streaming. Without it, Lambda treats the handler as a standard buffered response.
180
+
181
+ Source: www/docs/server/adapters/aws-lambda.md
182
+
183
+ ## See Also
184
+
185
+ - **server-setup** -- `initTRPC.create()`, router/procedure definition, context
186
+ - **adapter-fetch** -- alternative for edge/serverless runtimes using Fetch API
187
+ - **links** -- `httpBatchLink` vs `httpLink` for API Gateway routing considerations
188
+ - AWS Lambda docs: https://docs.aws.amazon.com/lambda/latest/dg/welcome.html
@@ -0,0 +1,152 @@
1
+ ---
2
+ name: adapter-express
3
+ description: >
4
+ Mount tRPC as Express middleware with createExpressMiddleware() from
5
+ @trpc/server/adapters/express. Access Express req/res in createContext via
6
+ CreateExpressContextOptions. Mount at a path prefix like app.use('/trpc', ...).
7
+ Avoid global express.json() conflicting with tRPC body parsing for FormData.
8
+ type: core
9
+ library: trpc
10
+ library_version: '11.14.0'
11
+ requires:
12
+ - server-setup
13
+ sources:
14
+ - www/docs/server/adapters/express.md
15
+ - examples/express-server/src/server.ts
16
+ ---
17
+
18
+ # tRPC — Adapter: Express
19
+
20
+ ## Setup
21
+
22
+ ```ts
23
+ // server.ts
24
+ import { initTRPC } from '@trpc/server';
25
+ import * as trpcExpress from '@trpc/server/adapters/express';
26
+ import express from 'express';
27
+ import { z } from 'zod';
28
+
29
+ const createContext = ({
30
+ req,
31
+ res,
32
+ }: trpcExpress.CreateExpressContextOptions) => {
33
+ return { req, res };
34
+ };
35
+ type Context = Awaited<ReturnType<typeof createContext>>;
36
+
37
+ const t = initTRPC.context<Context>().create();
38
+
39
+ const appRouter = t.router({
40
+ greet: t.procedure
41
+ .input(z.object({ name: z.string() }))
42
+ .query(({ input }) => ({ greeting: `Hello, ${input.name}!` })),
43
+ });
44
+
45
+ export type AppRouter = typeof appRouter;
46
+
47
+ const app = express();
48
+
49
+ app.use(
50
+ '/trpc',
51
+ trpcExpress.createExpressMiddleware({
52
+ router: appRouter,
53
+ createContext,
54
+ }),
55
+ );
56
+
57
+ app.listen(4000, () => {
58
+ console.log('Listening on http://localhost:4000');
59
+ });
60
+ ```
61
+
62
+ ## Core Patterns
63
+
64
+ ### Accessing Express req/res in context
65
+
66
+ ```ts
67
+ import * as trpcExpress from '@trpc/server/adapters/express';
68
+
69
+ const createContext = ({
70
+ req,
71
+ res,
72
+ }: trpcExpress.CreateExpressContextOptions) => {
73
+ const token = req.headers.authorization?.split(' ')[1];
74
+ return { token, res };
75
+ };
76
+
77
+ type Context = Awaited<ReturnType<typeof createContext>>;
78
+ ```
79
+
80
+ `CreateExpressContextOptions` provides typed access to the Express `req` (IncomingMessage) and `res` (ServerResponse).
81
+
82
+ ### Adding tRPC alongside existing Express routes
83
+
84
+ ```ts
85
+ import * as trpcExpress from '@trpc/server/adapters/express';
86
+ import cors from 'cors';
87
+ import express from 'express';
88
+ import { createContext } from './context';
89
+ import { appRouter } from './router';
90
+
91
+ const app = express();
92
+
93
+ app.use(cors());
94
+
95
+ app.get('/health', (_req, res) => {
96
+ res.json({ status: 'ok' });
97
+ });
98
+
99
+ app.use(
100
+ '/trpc',
101
+ trpcExpress.createExpressMiddleware({
102
+ router: appRouter,
103
+ createContext,
104
+ }),
105
+ );
106
+
107
+ app.listen(4000);
108
+ ```
109
+
110
+ ## Common Mistakes
111
+
112
+ ### HIGH Global express.json() consuming tRPC request body
113
+
114
+ Wrong:
115
+
116
+ ```ts
117
+ const app = express();
118
+ app.use(express.json()); // global body parser
119
+ app.use(
120
+ '/trpc',
121
+ trpcExpress.createExpressMiddleware({
122
+ router: appRouter,
123
+ createContext,
124
+ }),
125
+ );
126
+ ```
127
+
128
+ Correct:
129
+
130
+ ```ts
131
+ const app = express();
132
+ // Only apply body parser to non-tRPC routes
133
+ app.use('/api', express.json());
134
+ app.use(
135
+ '/trpc',
136
+ trpcExpress.createExpressMiddleware({
137
+ router: appRouter,
138
+ createContext,
139
+ }),
140
+ );
141
+ ```
142
+
143
+ If `express.json()` is applied globally before the tRPC middleware, it consumes and parses the request body. tRPC then receives an already-parsed body, which breaks FormData and binary content type handling.
144
+
145
+ Source: www/docs/server/non-json-content-types.md
146
+
147
+ ## See Also
148
+
149
+ - **server-setup** -- `initTRPC.create()`, router/procedure definition, context
150
+ - **adapter-standalone** -- simpler adapter when Express middleware ecosystem is not needed
151
+ - **auth** -- extracting JWT from `req.headers.authorization` in context
152
+ - Express docs: https://expressjs.com/en/guide/using-middleware.html
@@ -0,0 +1,206 @@
1
+ ---
2
+ name: adapter-fastify
3
+ description: >
4
+ Mount tRPC as a Fastify plugin with fastifyTRPCPlugin from
5
+ @trpc/server/adapters/fastify. Configure prefix, trpcOptions (router,
6
+ createContext, onError). Enable WebSocket subscriptions with useWSS and
7
+ @fastify/websocket. Set routerOptions.maxParamLength for batch requests.
8
+ Requires Fastify v5+. FastifyTRPCPluginOptions for type-safe onError.
9
+ CreateFastifyContextOptions provides req, res.
10
+ type: core
11
+ library: trpc
12
+ library_version: '11.14.0'
13
+ requires:
14
+ - server-setup
15
+ sources:
16
+ - www/docs/server/adapters/fastify.md
17
+ - examples/fastify-server/
18
+ ---
19
+
20
+ # tRPC — Adapter: Fastify
21
+
22
+ ## Setup
23
+
24
+ ```ts
25
+ // server.ts
26
+ import { initTRPC } from '@trpc/server';
27
+ import {
28
+ fastifyTRPCPlugin,
29
+ FastifyTRPCPluginOptions,
30
+ } from '@trpc/server/adapters/fastify';
31
+ import type { CreateFastifyContextOptions } from '@trpc/server/adapters/fastify';
32
+ import fastify from 'fastify';
33
+ import { z } from 'zod';
34
+
35
+ function createContext({ req, res }: CreateFastifyContextOptions) {
36
+ return { req, res };
37
+ }
38
+ type Context = Awaited<ReturnType<typeof createContext>>;
39
+
40
+ const t = initTRPC.context<Context>().create();
41
+
42
+ const appRouter = t.router({
43
+ greet: t.procedure
44
+ .input(z.object({ name: z.string() }))
45
+ .query(({ input }) => ({ greeting: `Hello, ${input.name}!` })),
46
+ });
47
+
48
+ export type AppRouter = typeof appRouter;
49
+
50
+ const server = fastify({
51
+ routerOptions: {
52
+ maxParamLength: 5000,
53
+ },
54
+ });
55
+
56
+ server.register(fastifyTRPCPlugin, {
57
+ prefix: '/trpc',
58
+ trpcOptions: {
59
+ router: appRouter,
60
+ createContext,
61
+ onError({ path, error }) {
62
+ console.error(`Error in tRPC handler on path '${path}':`, error);
63
+ },
64
+ } satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
65
+ });
66
+
67
+ (async () => {
68
+ try {
69
+ await server.listen({ port: 3000 });
70
+ console.log('Listening on http://localhost:3000');
71
+ } catch (err) {
72
+ server.log.error(err);
73
+ process.exit(1);
74
+ }
75
+ })();
76
+ ```
77
+
78
+ ## Core Patterns
79
+
80
+ ### WebSocket subscriptions with @fastify/websocket
81
+
82
+ ```ts
83
+ import ws from '@fastify/websocket';
84
+ import {
85
+ fastifyTRPCPlugin,
86
+ FastifyTRPCPluginOptions,
87
+ } from '@trpc/server/adapters/fastify';
88
+ import fastify from 'fastify';
89
+ import { createContext } from './context';
90
+ import { appRouter, type AppRouter } from './router';
91
+
92
+ const server = fastify({
93
+ routerOptions: { maxParamLength: 5000 },
94
+ });
95
+
96
+ // Register @fastify/websocket BEFORE the tRPC plugin
97
+ server.register(ws);
98
+
99
+ server.register(fastifyTRPCPlugin, {
100
+ prefix: '/trpc',
101
+ useWSS: true,
102
+ trpcOptions: {
103
+ router: appRouter,
104
+ createContext,
105
+ keepAlive: {
106
+ enabled: true,
107
+ pingMs: 30000,
108
+ pongWaitMs: 5000,
109
+ },
110
+ } satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
111
+ });
112
+
113
+ server.listen({ port: 3000 });
114
+ ```
115
+
116
+ Install: `npm install @fastify/websocket` (minimum version 3.11.0)
117
+
118
+ ### Type-safe onError with satisfies
119
+
120
+ ```ts
121
+ server.register(fastifyTRPCPlugin, {
122
+ prefix: '/trpc',
123
+ trpcOptions: {
124
+ router: appRouter,
125
+ createContext,
126
+ onError({ path, error, type, input }) {
127
+ console.error(`[${type}] ${path}:`, error.message);
128
+ },
129
+ } satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions'],
130
+ });
131
+ ```
132
+
133
+ Due to Fastify plugin type inference limitations, use `satisfies FastifyTRPCPluginOptions<AppRouter>['trpcOptions']` to get correct types on `onError` and other callbacks.
134
+
135
+ ## Common Mistakes
136
+
137
+ ### HIGH Registering @fastify/websocket after tRPC plugin
138
+
139
+ Wrong:
140
+
141
+ ```ts
142
+ server.register(fastifyTRPCPlugin, {
143
+ useWSS: true,
144
+ trpcOptions: { router: appRouter, createContext },
145
+ });
146
+ server.register(ws); // too late!
147
+ ```
148
+
149
+ Correct:
150
+
151
+ ```ts
152
+ server.register(ws); // register FIRST
153
+ server.register(fastifyTRPCPlugin, {
154
+ useWSS: true,
155
+ trpcOptions: { router: appRouter, createContext },
156
+ });
157
+ ```
158
+
159
+ The WebSocket plugin must be registered before the tRPC plugin. Reverse order causes WebSocket routes to not be recognized.
160
+
161
+ Source: www/docs/server/adapters/fastify.md
162
+
163
+ ### HIGH Missing maxParamLength for batch requests
164
+
165
+ Wrong:
166
+
167
+ ```ts
168
+ const server = fastify();
169
+ ```
170
+
171
+ Correct:
172
+
173
+ ```ts
174
+ const server = fastify({
175
+ routerOptions: { maxParamLength: 5000 },
176
+ });
177
+ ```
178
+
179
+ Fastify defaults to `maxParamLength: 100`. Batch requests from `httpBatchLink` encode multiple procedure names in the URL path parameter, which easily exceeds 100 characters and returns a 404.
180
+
181
+ Source: www/docs/server/adapters/fastify.md
182
+
183
+ ### CRITICAL Using Fastify v4 with tRPC v11
184
+
185
+ Wrong:
186
+
187
+ ```json
188
+ { "dependencies": { "fastify": "^4.0.0" } }
189
+ ```
190
+
191
+ Correct:
192
+
193
+ ```json
194
+ { "dependencies": { "fastify": "^5.0.0" } }
195
+ ```
196
+
197
+ tRPC v11 requires Fastify v5+. Fastify v4 may return empty responses without errors due to incompatible response handling.
198
+
199
+ Source: www/docs/server/adapters/fastify.md
200
+
201
+ ## See Also
202
+
203
+ - **server-setup** -- `initTRPC.create()`, router/procedure definition, context
204
+ - **subscriptions** -- async generator subscriptions, `tracked()`, `keepAlive`
205
+ - **adapter-standalone** -- simpler adapter when Fastify features are not needed
206
+ - Fastify docs: https://fastify.dev/docs/latest/