@trpc/client 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/README.md +8 -0
- package/bin/intent.js +20 -0
- package/dist/{httpBatchLink.d-B6vCg-F-.d.mts → httpBatchLink.d-p8Y9QM8p.d.mts} +3 -3
- package/dist/{httpBatchLink.d-B6vCg-F-.d.mts.map → httpBatchLink.d-p8Y9QM8p.d.mts.map} +1 -1
- package/dist/{httpLink.d-CVOTlkUT.d.mts → httpLink.d-CjpPCq4q.d.mts} +3 -3
- package/dist/{httpLink.d-CVOTlkUT.d.mts.map → httpLink.d-CjpPCq4q.d.mts.map} +1 -1
- package/dist/{httpUtils.d-yYSKGhiS.d.mts → httpUtils.d-C5t5to0D.d.mts} +2 -2
- package/dist/{httpUtils.d-yYSKGhiS.d.mts.map → httpUtils.d-C5t5to0D.d.mts.map} +1 -1
- package/dist/index.d.mts +7 -7
- package/dist/links/httpBatchLink.d.mts +3 -3
- package/dist/links/httpLink.d.mts +3 -3
- package/dist/links/loggerLink.d.mts +2 -2
- package/dist/links/splitLink.d.mts +2 -2
- package/dist/links/wsLink/wsLink.d.mts +2 -2
- package/dist/{loggerLink.d-DBRq_5Gd.d.mts → loggerLink.d-0ABgt7oh.d.mts} +2 -2
- package/dist/{loggerLink.d-DBRq_5Gd.d.mts.map → loggerLink.d-0ABgt7oh.d.mts.map} +1 -1
- package/dist/{splitLink.d-BKr9eE0o.d.mts → splitLink.d-CkHNg1Se.d.mts} +2 -2
- package/dist/{splitLink.d-BKr9eE0o.d.mts.map → splitLink.d-CkHNg1Se.d.mts.map} +1 -1
- package/dist/{types.d-sRNtuQA-.d.mts → types.d-CAr6snH0.d.mts} +2 -2
- package/dist/{types.d-sRNtuQA-.d.mts.map → types.d-CAr6snH0.d.mts.map} +1 -1
- package/dist/{wsLink.d-DCqbZKOH.d.mts → wsLink.d-pFN64NkG.d.mts} +2 -2
- package/dist/{wsLink.d-DCqbZKOH.d.mts.map → wsLink.d-pFN64NkG.d.mts.map} +1 -1
- package/package.json +15 -5
- package/skills/client-setup/SKILL.md +317 -0
- package/skills/links/SKILL.md +300 -0
- package/skills/links/references/link-options.md +248 -0
- package/skills/superjson/SKILL.md +273 -0
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: links
|
|
3
|
+
description: >
|
|
4
|
+
Configure the tRPC client link chain: httpLink, httpBatchLink,
|
|
5
|
+
httpBatchStreamLink, splitLink, loggerLink, wsLink, createWSClient,
|
|
6
|
+
httpSubscriptionLink, unstable_localLink, retryLink. Choose the right
|
|
7
|
+
terminating link. Route subscriptions via splitLink. Build custom links
|
|
8
|
+
for SOA routing. Link options: url, headers, transformer, maxURLLength,
|
|
9
|
+
maxItems, connectionParams, EventSource ponyfill.
|
|
10
|
+
type: core
|
|
11
|
+
library: trpc
|
|
12
|
+
library_version: '11.14.0'
|
|
13
|
+
requires:
|
|
14
|
+
- client-setup
|
|
15
|
+
sources:
|
|
16
|
+
- www/docs/client/links/overview.md
|
|
17
|
+
- www/docs/client/links/httpLink.md
|
|
18
|
+
- www/docs/client/links/httpBatchLink.md
|
|
19
|
+
- www/docs/client/links/httpBatchStreamLink.md
|
|
20
|
+
- www/docs/client/links/splitLink.mdx
|
|
21
|
+
- www/docs/client/links/wsLink.md
|
|
22
|
+
- www/docs/client/links/httpSubscriptionLink.md
|
|
23
|
+
- www/docs/client/links/localLink.mdx
|
|
24
|
+
- www/docs/client/links/loggerLink.md
|
|
25
|
+
- packages/client/src/links/
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
# tRPC -- Links
|
|
29
|
+
|
|
30
|
+
## Setup
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import { createTRPCClient, httpBatchLink, loggerLink } from '@trpc/client';
|
|
34
|
+
import type { AppRouter } from './server';
|
|
35
|
+
|
|
36
|
+
const client = createTRPCClient<AppRouter>({
|
|
37
|
+
links: [
|
|
38
|
+
loggerLink(),
|
|
39
|
+
httpBatchLink({
|
|
40
|
+
url: 'http://localhost:3000/trpc',
|
|
41
|
+
}),
|
|
42
|
+
],
|
|
43
|
+
});
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
The `links` array is a chain: non-terminating links (loggerLink, splitLink, retryLink) forward operations; the chain must end with a terminating link (httpBatchLink, httpLink, httpBatchStreamLink, wsLink, httpSubscriptionLink, unstable_localLink).
|
|
47
|
+
|
|
48
|
+
## Core Patterns
|
|
49
|
+
|
|
50
|
+
### httpBatchLink -- Batch Multiple Calls into One Request
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import { createTRPCClient, httpBatchLink } from '@trpc/client';
|
|
54
|
+
import type { AppRouter } from './server';
|
|
55
|
+
|
|
56
|
+
const client = createTRPCClient<AppRouter>({
|
|
57
|
+
links: [
|
|
58
|
+
httpBatchLink({
|
|
59
|
+
url: 'http://localhost:3000/trpc',
|
|
60
|
+
maxURLLength: 2083,
|
|
61
|
+
maxItems: 10,
|
|
62
|
+
}),
|
|
63
|
+
],
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const [post1, post2, post3] = await Promise.all([
|
|
67
|
+
client.post.byId.query(1),
|
|
68
|
+
client.post.byId.query(2),
|
|
69
|
+
client.post.byId.query(3),
|
|
70
|
+
]);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Concurrent calls are batched into a single HTTP request. Set `maxURLLength` to prevent 414 errors from long URLs.
|
|
74
|
+
|
|
75
|
+
### splitLink -- Route Subscriptions to SSE
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import {
|
|
79
|
+
createTRPCClient,
|
|
80
|
+
httpBatchLink,
|
|
81
|
+
httpSubscriptionLink,
|
|
82
|
+
splitLink,
|
|
83
|
+
} from '@trpc/client';
|
|
84
|
+
import type { AppRouter } from './server';
|
|
85
|
+
|
|
86
|
+
const client = createTRPCClient<AppRouter>({
|
|
87
|
+
links: [
|
|
88
|
+
splitLink({
|
|
89
|
+
condition: (op) => op.type === 'subscription',
|
|
90
|
+
true: httpSubscriptionLink({
|
|
91
|
+
url: 'http://localhost:3000/trpc',
|
|
92
|
+
}),
|
|
93
|
+
false: httpBatchLink({
|
|
94
|
+
url: 'http://localhost:3000/trpc',
|
|
95
|
+
}),
|
|
96
|
+
}),
|
|
97
|
+
],
|
|
98
|
+
});
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### splitLink -- Disable Batching Per-Request via Context
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
import {
|
|
105
|
+
createTRPCClient,
|
|
106
|
+
httpBatchLink,
|
|
107
|
+
httpLink,
|
|
108
|
+
splitLink,
|
|
109
|
+
} from '@trpc/client';
|
|
110
|
+
import type { AppRouter } from './server';
|
|
111
|
+
|
|
112
|
+
const client = createTRPCClient<AppRouter>({
|
|
113
|
+
links: [
|
|
114
|
+
splitLink({
|
|
115
|
+
condition: (op) => Boolean(op.context.skipBatch),
|
|
116
|
+
true: httpLink({ url: 'http://localhost:3000/trpc' }),
|
|
117
|
+
false: httpBatchLink({ url: 'http://localhost:3000/trpc' }),
|
|
118
|
+
}),
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const result = await client.post.byId.query(1, {
|
|
123
|
+
context: { skipBatch: true },
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### httpBatchStreamLink -- Stream Responses as They Arrive
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
import { createTRPCClient, httpBatchStreamLink } from '@trpc/client';
|
|
131
|
+
import type { AppRouter } from './server';
|
|
132
|
+
|
|
133
|
+
const client = createTRPCClient<AppRouter>({
|
|
134
|
+
links: [
|
|
135
|
+
httpBatchStreamLink({
|
|
136
|
+
url: 'http://localhost:3000/trpc',
|
|
137
|
+
}),
|
|
138
|
+
],
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const iterable = await client.examples.iterable.query();
|
|
142
|
+
for await (const value of iterable) {
|
|
143
|
+
console.log(value);
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
### wsLink -- WebSocket Terminating Link
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
import { createTRPCClient, createWSClient, wsLink } from '@trpc/client';
|
|
151
|
+
import type { AppRouter } from './server';
|
|
152
|
+
|
|
153
|
+
const wsClient = createWSClient({
|
|
154
|
+
url: 'ws://localhost:3000',
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const client = createTRPCClient<AppRouter>({
|
|
158
|
+
links: [wsLink<AppRouter>({ client: wsClient })],
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Custom Link
|
|
163
|
+
|
|
164
|
+
```ts
|
|
165
|
+
import { TRPCLink } from '@trpc/client';
|
|
166
|
+
import { observable } from '@trpc/server/observable';
|
|
167
|
+
import type { AppRouter } from './server';
|
|
168
|
+
|
|
169
|
+
export const timingLink: TRPCLink<AppRouter> = () => {
|
|
170
|
+
return ({ next, op }) => {
|
|
171
|
+
return observable((observer) => {
|
|
172
|
+
const start = Date.now();
|
|
173
|
+
const unsubscribe = next(op).subscribe({
|
|
174
|
+
next(value) {
|
|
175
|
+
observer.next(value);
|
|
176
|
+
},
|
|
177
|
+
error(err) {
|
|
178
|
+
console.error(`${op.path} failed in ${Date.now() - start}ms`);
|
|
179
|
+
observer.error(err);
|
|
180
|
+
},
|
|
181
|
+
complete() {
|
|
182
|
+
console.log(`${op.path} completed in ${Date.now() - start}ms`);
|
|
183
|
+
observer.complete();
|
|
184
|
+
},
|
|
185
|
+
});
|
|
186
|
+
return unsubscribe;
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
## Common Mistakes
|
|
193
|
+
|
|
194
|
+
### [CRITICAL] No terminating link in the chain
|
|
195
|
+
|
|
196
|
+
Wrong:
|
|
197
|
+
|
|
198
|
+
```ts
|
|
199
|
+
const client = createTRPCClient<AppRouter>({
|
|
200
|
+
links: [loggerLink()],
|
|
201
|
+
});
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
Correct:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
const client = createTRPCClient<AppRouter>({
|
|
208
|
+
links: [loggerLink(), httpBatchLink({ url: 'http://localhost:3000/trpc' })],
|
|
209
|
+
});
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
The link chain must end with a terminating link. Without one, tRPC throws "No more links to execute - did you forget to add an ending link?"
|
|
213
|
+
|
|
214
|
+
Source: packages/client/src/links/internals/createChain.ts
|
|
215
|
+
|
|
216
|
+
### [CRITICAL] Sending subscriptions through httpLink or httpBatchLink
|
|
217
|
+
|
|
218
|
+
Wrong:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
const client = createTRPCClient<AppRouter>({
|
|
222
|
+
links: [httpBatchLink({ url: 'http://localhost:3000/trpc' })],
|
|
223
|
+
});
|
|
224
|
+
await client.onMessage.subscribe({});
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Correct:
|
|
228
|
+
|
|
229
|
+
```ts
|
|
230
|
+
const client = createTRPCClient<AppRouter>({
|
|
231
|
+
links: [
|
|
232
|
+
splitLink({
|
|
233
|
+
condition: (op) => op.type === 'subscription',
|
|
234
|
+
true: httpSubscriptionLink({ url: 'http://localhost:3000/trpc' }),
|
|
235
|
+
false: httpBatchLink({ url: 'http://localhost:3000/trpc' }),
|
|
236
|
+
}),
|
|
237
|
+
],
|
|
238
|
+
});
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
httpLink and httpBatchLink throw on subscription operations. Subscriptions must use httpSubscriptionLink or wsLink, routed via splitLink.
|
|
242
|
+
|
|
243
|
+
Source: packages/client/src/links/httpLink.ts
|
|
244
|
+
|
|
245
|
+
### [HIGH] httpBatchLink and httpBatchStreamLink headers callback receives { opList }
|
|
246
|
+
|
|
247
|
+
`httpBatchLink` and `httpBatchStreamLink` headers callbacks receive `{ opList }` (a `NonEmptyArray<Operation>`), not `{ op }` like `httpLink`. Access per-operation context via `opList[0]?.context`:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
httpBatchLink({
|
|
251
|
+
url: 'http://localhost:3000/trpc',
|
|
252
|
+
headers({ opList }) {
|
|
253
|
+
return { authorization: opList[0]?.context.token };
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
`httpBatchLink` headers callback receives `{ opList }` (an array of operations)
|
|
259
|
+
|
|
260
|
+
Source: packages/client/src/links/httpBatchLink.ts
|
|
261
|
+
|
|
262
|
+
### [MEDIUM] Default batch limits are Infinity
|
|
263
|
+
|
|
264
|
+
Wrong:
|
|
265
|
+
|
|
266
|
+
```ts
|
|
267
|
+
httpBatchLink({ url: 'http://localhost:3000/trpc' });
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
Correct:
|
|
271
|
+
|
|
272
|
+
```ts
|
|
273
|
+
httpBatchLink({
|
|
274
|
+
url: 'http://localhost:3000/trpc',
|
|
275
|
+
maxURLLength: 2083,
|
|
276
|
+
maxItems: 10,
|
|
277
|
+
});
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
Both `maxURLLength` and `maxItems` default to `Infinity`, which can cause 413/414 HTTP errors on servers or CDNs with URL length limits.
|
|
281
|
+
|
|
282
|
+
Source: packages/client/src/links/httpBatchLink.ts
|
|
283
|
+
|
|
284
|
+
### [HIGH] httpBatchStreamLink data loss on stream completion
|
|
285
|
+
|
|
286
|
+
There is a known race condition where buffered chunks can be lost on normal stream completion. Long streaming responses (e.g., LLM output) may be truncated. If you experience truncated data, switch to `httpBatchLink` for those operations.
|
|
287
|
+
|
|
288
|
+
Source: https://github.com/trpc/trpc/issues/7209
|
|
289
|
+
|
|
290
|
+
## References
|
|
291
|
+
|
|
292
|
+
- [Link options reference](references/link-options.md)
|
|
293
|
+
|
|
294
|
+
## See Also
|
|
295
|
+
|
|
296
|
+
- `client-setup` -- create the tRPC client and configure links
|
|
297
|
+
- `superjson` -- add transformer to links for Date/Map/Set support
|
|
298
|
+
- `subscriptions` -- set up SSE or WebSocket real-time streams
|
|
299
|
+
- `non-json-content-types` -- route FormData/binary through splitLink + httpLink
|
|
300
|
+
- `service-oriented-architecture` -- build custom routing links for multi-service backends
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Link Options Reference
|
|
2
|
+
|
|
3
|
+
## httpLink
|
|
4
|
+
|
|
5
|
+
Terminating link that sends one tRPC operation per HTTP request.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import { httpLink } from '@trpc/client';
|
|
9
|
+
|
|
10
|
+
httpLink({
|
|
11
|
+
url: 'http://localhost:3000/trpc',
|
|
12
|
+
fetch: customFetch,
|
|
13
|
+
transformer: superjson,
|
|
14
|
+
headers: { Authorization: 'Bearer token' },
|
|
15
|
+
methodOverride: 'POST',
|
|
16
|
+
});
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
| Option | Type | Default | Description |
|
|
20
|
+
| ---------------- | --------------------------------------------------------------------------------- | -------------- | --------------------------------------------- |
|
|
21
|
+
| `url` | `string \| URL` | required | Server endpoint URL |
|
|
22
|
+
| `fetch` | `typeof fetch` | global `fetch` | Fetch ponyfill |
|
|
23
|
+
| `transformer` | `DataTransformerOptions` | none | Data transformer (e.g. superjson) |
|
|
24
|
+
| `headers` | `HTTPHeaders \| (opts: { op: Operation }) => HTTPHeaders \| Promise<HTTPHeaders>` | `{}` | Static headers object or per-request callback |
|
|
25
|
+
| `methodOverride` | `'POST'` | none | Force all requests as POST |
|
|
26
|
+
|
|
27
|
+
## httpBatchLink
|
|
28
|
+
|
|
29
|
+
Terminating link that batches multiple operations into a single HTTP request.
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
import { httpBatchLink } from '@trpc/client';
|
|
33
|
+
|
|
34
|
+
httpBatchLink({
|
|
35
|
+
url: 'http://localhost:3000/trpc',
|
|
36
|
+
maxURLLength: 2083,
|
|
37
|
+
maxItems: 10,
|
|
38
|
+
headers({ opList }) {
|
|
39
|
+
return { Authorization: `Bearer ${opList[0]?.context.token}` };
|
|
40
|
+
},
|
|
41
|
+
transformer: superjson,
|
|
42
|
+
});
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Option | Type | Default | Description |
|
|
46
|
+
| ---------------- | --------------------------------------------------------------------------------------- | -------------- | ---------------------------------------------------- |
|
|
47
|
+
| `url` | `string \| URL` | required | Server endpoint URL |
|
|
48
|
+
| `fetch` | `typeof fetch` | global `fetch` | Fetch ponyfill |
|
|
49
|
+
| `transformer` | `DataTransformerOptions` | none | Data transformer |
|
|
50
|
+
| `headers` | `HTTPHeaders \| (opts: { opList: Operation[] }) => HTTPHeaders \| Promise<HTTPHeaders>` | `{}` | Headers callback receives `opList` (array), not `op` |
|
|
51
|
+
| `maxURLLength` | `number` | `Infinity` | Split batch if URL exceeds this length |
|
|
52
|
+
| `maxItems` | `number` | `Infinity` | Maximum operations per batch |
|
|
53
|
+
| `methodOverride` | `'POST'` | none | Force all requests as POST |
|
|
54
|
+
|
|
55
|
+
## httpBatchStreamLink
|
|
56
|
+
|
|
57
|
+
Terminating link similar to httpBatchLink but streams responses as they arrive instead of waiting for all to complete.
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
import { httpBatchStreamLink } from '@trpc/client';
|
|
61
|
+
|
|
62
|
+
httpBatchStreamLink({
|
|
63
|
+
url: 'http://localhost:3000/trpc',
|
|
64
|
+
maxURLLength: 2083,
|
|
65
|
+
maxItems: 10,
|
|
66
|
+
transformer: superjson,
|
|
67
|
+
streamHeader: 'accept',
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
| Option | Type | Default | Description |
|
|
72
|
+
| --------------------------- | --------------------------- | --------------- | ------------------------------------------------------------------------------------------------- |
|
|
73
|
+
| All `httpBatchLink` options | | | Inherits all httpBatchLink options |
|
|
74
|
+
| `streamHeader` | `'trpc-accept' \| 'accept'` | `'trpc-accept'` | Header used to signal streaming. Use `'accept'` to avoid CORS preflight on cross-origin requests. |
|
|
75
|
+
|
|
76
|
+
Sends `trpc-accept: application/jsonl` (or `Accept: application/jsonl`). Response arrives as `transfer-encoding: chunked` with `content-type: application/jsonl`. Cannot set response headers (including cookies) after stream begins.
|
|
77
|
+
|
|
78
|
+
## splitLink
|
|
79
|
+
|
|
80
|
+
Non-terminating link that branches the link chain based on a condition.
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
import {
|
|
84
|
+
httpBatchLink,
|
|
85
|
+
httpLink,
|
|
86
|
+
httpSubscriptionLink,
|
|
87
|
+
splitLink,
|
|
88
|
+
} from '@trpc/client';
|
|
89
|
+
|
|
90
|
+
splitLink({
|
|
91
|
+
condition: (op) => op.type === 'subscription',
|
|
92
|
+
true: httpSubscriptionLink({ url }),
|
|
93
|
+
false: httpBatchLink({ url }),
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
| Option | Type | Default | Description |
|
|
98
|
+
| ----------- | ---------------------------- | -------- | ------------------------------------------------------------- |
|
|
99
|
+
| `condition` | `(op: Operation) => boolean` | required | Route predicate |
|
|
100
|
+
| `true` | `TRPCLink \| TRPCLink[]` | required | Link(s) for condition=true. Must include a terminating link. |
|
|
101
|
+
| `false` | `TRPCLink \| TRPCLink[]` | required | Link(s) for condition=false. Must include a terminating link. |
|
|
102
|
+
|
|
103
|
+
Each branch creates its own sub-chain, so both branches need a terminating link.
|
|
104
|
+
|
|
105
|
+
## loggerLink
|
|
106
|
+
|
|
107
|
+
Non-terminating link that logs operations to the console.
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
import { loggerLink } from '@trpc/client';
|
|
111
|
+
|
|
112
|
+
loggerLink({
|
|
113
|
+
enabled: (opts) =>
|
|
114
|
+
(process.env.NODE_ENV === 'development' && typeof window !== 'undefined') ||
|
|
115
|
+
(opts.direction === 'down' && opts.result instanceof Error),
|
|
116
|
+
colorMode: 'ansi',
|
|
117
|
+
});
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
| Option | Type | Default | Description |
|
|
121
|
+
| ------------- | -------------------------------------------------------------------- | ------------------------------------ | -------------------------------- |
|
|
122
|
+
| `enabled` | `(opts: { direction: 'up' \| 'down'; result?: unknown }) => boolean` | `() => true` | Control when logging is active |
|
|
123
|
+
| `logger` | `(opts: LoggerOpts) => void` | built-in pretty logger | Custom log function |
|
|
124
|
+
| `console` | `{ log: Function; error: Function }` | `globalThis.console` | Console implementation |
|
|
125
|
+
| `colorMode` | `'ansi' \| 'css' \| 'none'` | `'css'` in browser, `'ansi'` in Node | Color output mode |
|
|
126
|
+
| `withContext` | `boolean` | `false` (true if css) | Include operation context in log |
|
|
127
|
+
|
|
128
|
+
## retryLink
|
|
129
|
+
|
|
130
|
+
Non-terminating link that retries failed operations.
|
|
131
|
+
|
|
132
|
+
```ts
|
|
133
|
+
import { retryLink } from '@trpc/client';
|
|
134
|
+
|
|
135
|
+
retryLink({
|
|
136
|
+
retry(opts) {
|
|
137
|
+
if (opts.error.data?.code === 'INTERNAL_SERVER_ERROR') {
|
|
138
|
+
return opts.attempts <= 3;
|
|
139
|
+
}
|
|
140
|
+
return false;
|
|
141
|
+
},
|
|
142
|
+
retryDelayMs: (attempt) => Math.min(1000 * 2 ** attempt, 30000),
|
|
143
|
+
});
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Option | Type | Default | Description |
|
|
147
|
+
| -------------- | -------------------------------------------- | --------- | --------------------------- |
|
|
148
|
+
| `retry` | `(opts: { op, error, attempts }) => boolean` | required | Return true to retry |
|
|
149
|
+
| `retryDelayMs` | `(attempt: number) => number` | `() => 0` | Delay between retries in ms |
|
|
150
|
+
|
|
151
|
+
When used with subscriptions that use `tracked()`, automatically includes the last known event ID on retry.
|
|
152
|
+
|
|
153
|
+
## wsLink
|
|
154
|
+
|
|
155
|
+
Terminating link for WebSocket connections. Requires a `TRPCWebSocketClient`.
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { createWSClient, wsLink } from '@trpc/client';
|
|
159
|
+
|
|
160
|
+
const wsClient = createWSClient({
|
|
161
|
+
url: 'ws://localhost:3000',
|
|
162
|
+
connectionParams: () => ({ token: 'supersecret' }),
|
|
163
|
+
lazy: { enabled: true, closeMs: 10_000 },
|
|
164
|
+
keepAlive: { enabled: true, intervalMs: 5_000, pongTimeoutMs: 1_000 },
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
wsLink<AppRouter>({
|
|
168
|
+
client: wsClient,
|
|
169
|
+
transformer: superjson,
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### wsLink Options
|
|
174
|
+
|
|
175
|
+
| Option | Type | Default | Description |
|
|
176
|
+
| ------------- | ------------------------ | -------- | ------------------------------------ |
|
|
177
|
+
| `client` | `TRPCWebSocketClient` | required | WebSocket client from createWSClient |
|
|
178
|
+
| `transformer` | `DataTransformerOptions` | none | Data transformer |
|
|
179
|
+
|
|
180
|
+
### createWSClient Options
|
|
181
|
+
|
|
182
|
+
| Option | Type | Default | Description |
|
|
183
|
+
| ------------------------- | ---------------------------------------------------------------------------------------- | ------------------- | ----------------------------------------------------------------- |
|
|
184
|
+
| `url` | `string \| (() => MaybePromise<string>)` | required | WebSocket server URL |
|
|
185
|
+
| `connectionParams` | `Record<string, string> \| null \| (() => MaybePromise<Record<string, string> \| null>)` | `null` | Auth params sent as first message, available in `createContext()` |
|
|
186
|
+
| `WebSocket` | `typeof WebSocket` | global `WebSocket` | WebSocket ponyfill |
|
|
187
|
+
| `retryDelayMs` | `(attemptIndex: number) => number` | exponential backoff | Reconnection delay |
|
|
188
|
+
| `onOpen` | `() => void` | none | Connection opened callback |
|
|
189
|
+
| `onError` | `(evt?: Event) => void` | none | Connection error callback |
|
|
190
|
+
| `onClose` | `(cause?: { code?: number }) => void` | none | Connection closed callback |
|
|
191
|
+
| `lazy.enabled` | `boolean` | `false` | Close WS after inactivity |
|
|
192
|
+
| `lazy.closeMs` | `number` | `0` | Idle timeout before closing |
|
|
193
|
+
| `keepAlive.enabled` | `boolean` | `false` | Send ping messages |
|
|
194
|
+
| `keepAlive.intervalMs` | `number` | `5000` | Ping interval |
|
|
195
|
+
| `keepAlive.pongTimeoutMs` | `number` | `1000` | Close if no pong within this time |
|
|
196
|
+
|
|
197
|
+
## httpSubscriptionLink
|
|
198
|
+
|
|
199
|
+
Terminating link for Server-Sent Events (SSE) subscriptions.
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { httpSubscriptionLink } from '@trpc/client';
|
|
203
|
+
import { EventSourcePolyfill } from 'event-source-polyfill';
|
|
204
|
+
|
|
205
|
+
httpSubscriptionLink({
|
|
206
|
+
url: 'http://localhost:3000/trpc',
|
|
207
|
+
connectionParams: async () => ({ token: 'supersecret' }),
|
|
208
|
+
transformer: superjson,
|
|
209
|
+
EventSource: EventSourcePolyfill,
|
|
210
|
+
eventSourceOptions: async ({ op }) => ({
|
|
211
|
+
headers: {
|
|
212
|
+
authorization: 'Bearer token',
|
|
213
|
+
},
|
|
214
|
+
}),
|
|
215
|
+
});
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
| Option | Type | Default | Description |
|
|
219
|
+
| -------------------- | ------------------------------------------------------------------------------------ | -------------------- | ----------------------------------------- |
|
|
220
|
+
| `url` | `string \| (() => string \| Promise<string>)` | required | Server endpoint URL |
|
|
221
|
+
| `connectionParams` | `Record<string, string> \| null \| (() => MaybePromise<...>)` | none | Serialized as URL query param |
|
|
222
|
+
| `transformer` | `DataTransformerOptions` | none | Data transformer |
|
|
223
|
+
| `EventSource` | EventSource constructor | global `EventSource` | EventSource ponyfill for custom headers |
|
|
224
|
+
| `eventSourceOptions` | `EventSourceInit \| ((opts: { op }) => EventSourceInit \| Promise<EventSourceInit>)` | none | Options passed to EventSource constructor |
|
|
225
|
+
|
|
226
|
+
For cross-domain cookies, use `eventSourceOptions: () => ({ withCredentials: true })`.
|
|
227
|
+
|
|
228
|
+
## unstable_localLink
|
|
229
|
+
|
|
230
|
+
Terminating link for direct procedure calls without HTTP. Useful for testing and server-side usage.
|
|
231
|
+
|
|
232
|
+
```ts
|
|
233
|
+
import { unstable_localLink } from '@trpc/client';
|
|
234
|
+
import { appRouter } from './server';
|
|
235
|
+
|
|
236
|
+
unstable_localLink({
|
|
237
|
+
router: appRouter,
|
|
238
|
+
createContext: async () => ({ db: prisma }),
|
|
239
|
+
onError: (opts) => console.error('Error:', opts.error),
|
|
240
|
+
});
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
| Option | Type | Default | Description |
|
|
244
|
+
| --------------- | ------------------------------------- | -------- | ------------------------ |
|
|
245
|
+
| `router` | `AnyRouter` | required | tRPC router instance |
|
|
246
|
+
| `createContext` | `() => Promise<Context>` | required | Context factory per call |
|
|
247
|
+
| `onError` | `(opts: ErrorHandlerOptions) => void` | none | Error handler |
|
|
248
|
+
| `transformer` | `DataTransformerOptions` | none | Data transformer |
|