new·The score now tells you which way it movedA brain's exam only ever grows: its own material writes questions, and so does every question a real caller asked and did not get answered. The score is a percentage over that growing set, so a brain that learned more could post a smaller number — and this week three did. One of them answered two MORE questions than the week before and showed eighteen points less. Printed as a single percentage, that reads as decline to a reader and as punishment to anyone who contributes material.all news →
mozg.beta
Sign in

tRPC · all subjects

client/links

116 notes in this subject, read out of this brain and free to use. This is page 1 of 2.

httpBatchStreamLink batching with Promise.all

When using httpBatchStreamLink, you can batch multiple procedure calls by setting them in a Promise.all. This produces exactly one HTTP request and on the server exactly one database query.

httpBatchStreamLink HTTP headers and streaming

When using httpBatchStreamLink, requests are sent with a 'trpc-accept: application/jsonl' header (or 'Accept: application/jsonl' when using streamHeader: 'accept'), and the response is sent with 'transfer-encoding: chunked' and 'content-type: application/jsonl'.

httpBatchStreamLink incompatible with response header changes

If you require the ability to change or set response headers (which includes cookies) from within your procedures, you must use httpBatchLink instead of httpBatchStreamLink, because httpBatchStreamLink does not support setting headers once the stream has begun.

httpBatchStreamLink responseMeta behavior with streaming

With httpBatchStreamLink, the data key is removed from the argument object passed to responseMeta because with a streamed response, headers are sent before the data is available.

httpBatchStreamLink with async generators

httpBatchStreamLink supports async generator functions in procedures. A procedure can use 'async function*' to yield values over time, and the client can iterate over the results using 'for await (const value of iterable)'.

httpBatchStreamLink browser compatibility

httpBatchStreamLink browser support is identical to fetch support.

httpBatchStreamLink Node.js and Deno requirements

For runtimes other than browsers, the fetch implementation must support streaming with a response.body property that is either a ReadableStream<Uint8Array> with a getReader function, or a Uint8Array Buffer. This includes support for undici, node-fetch, native Node.js fetch, and WebAPI fetch (browsers).

httpBatchStreamLink React Native compatibility issue

httpBatchStreamLink receiving streams relies on TextDecoder and TextDecoderStream APIs, which are not available in React Native. You must polyfill these APIs, and may also need to polyfill ReadableStream and WritableStream. You will also need to override the default fetch in the httpBatchStreamLink configuration.

httpBatchStreamLink React Native fetch override example

To use httpBatchStreamLink in React Native with Expo, override the fetch option: httpBatchStreamLink({ fetch: (url, opts) => fetch(url, { ...opts, reactNative: { textStreaming: true } }), url: 'http://localhost:3000' })

httpBatchStreamLink AWS Lambda compatibility

httpBatchStreamLink is only supported on AWS Lambda when your infrastructure is set up for streaming responses. If not configured for streaming, the link will simply behave like a regular httpBatchLink.

httpBatchStreamLink Cloudflare Workers requirement

To use httpBatchStreamLink with Cloudflare Workers, you need to enable the ReadableStream API through the 'streams_enable_constructors' feature flag.

httpBatchStreamLink basic setup example

Example of setting up httpBatchStreamLink: const client = createTRPCClient<AppRouter>({ links: [ httpBatchStreamLink({ url: 'http://localhost:3000' }) ] })

httpBatchStreamLink ping option to keep connection alive

You can configure a ping option in the root tRPC config to keep the connection alive when using httpBatchStreamLink by passing a jsonl option with pingMs: const t = initTRPC.create({ jsonl: { pingMs: 1000 } })

httpBatchStreamLink - terminating link that batches with streaming

httpBatchStreamLink is a terminating link that batches an array of individual tRPC operations into a single HTTP request sent to a single tRPC procedure, equivalent to httpBatchLink, but streams responses as soon as any data is available instead of waiting for all responses to be ready.

httpBatchStreamLink streamHeader option

The streamHeader option for httpBatchStreamLink can be set to 'trpc-accept' (default) or 'accept'. The 'accept' option uses the standard Accept header instead of the custom trpc-accept header, which avoids CORS preflight for cross-origin streaming queries since Accept is a CORS-safelisted header.

httpBatchStreamLink vs httpBatchLink response behavior

Unlike httpBatchLink which waits for all requests to finish before sending the response, httpBatchStreamLink sends responses as soon as they are ready. This is useful for long-running requests.

Operation type structure for batching

An Operation object has the shape: { id: number; type: 'query' | 'mutation' | 'subscription'; path: string; input: unknown }. This is used internally when batching operations and is passed to header callback functions via the opList parameter.

maxItems option example

const client = createTRPCClient<AppRouter>({ links: [ httpBatchLink({ url: 'http://localhost:3000', maxItems: 10, }), ], });

Disable batching on server with allowBatching option

Set allowBatching: false on the server adapter to disable batching. For standalone: createHTTPServer({ allowBatching: false }). For Next.js: createNextApiHandler({ allowBatching: false }).

Replace httpBatchLink with httpLink to disable batching on client

To disable request batching on the client side, replace httpBatchLink with httpLink in the tRPC client configuration. httpLink sends individual requests instead of batching them.

httpBatchLink overview and batching behavior

httpBatchLink is a terminating link that batches an array of individual tRPC operations into a single HTTP request sent to a single tRPC procedure. When procedures are set in a Promise.all, it produces exactly one HTTP request and on the server exactly one database query.

HTTPBatchLinkOptions interface parameters

HTTPBatchLinkOptions extends HTTPLinkOptions and includes: maxURLLength (number, default Infinity) - Maximum length of HTTP URL allowed before operations are split into multiple requests; maxItems (number, default Infinity) - Maximum number of operations allowed in a single batch request.

HTTPLinkOptions interface parameters

HTTPLinkOptions includes: url (string | URL, required) - The endpoint URL; fetch (typeof fetch, optional) - Ponyfill for fetch; transformer (DataTransformerOptions, optional) - Data transformer for serialization; headers (HTTPHeaders | function, optional) - Headers to be set on outgoing requests or a callback that returns headers, where the callback receives opts with opList of type NonEmptyArray<Operation>.

Batch multiple queries with Promise.all example

const somePosts = await Promise.all([ trpc.post.byId.query(1), trpc.post.byId.query(2), trpc.post.byId.query(3), ]); This produces exactly one HTTP request.

maxURLLength option to prevent HTTP errors

When sending batch requests, the URL can become too large causing HTTP errors like 413 Payload Too Large, 414 URI Too Long, and 404 Not Found. The maxURLLength option limits the number of requests that can be sent together in a batch. A suitable value is 2083.

Set maximum batch size on server

maxBatchSize limits how many operations may be sent in a single batch request. Requests exceeding this limit are rejected with a 400 Bad Request error. This can be passed to any tRPC adapter, such as createHTTPServer({ maxBatchSize: 10 }) or trpcNext.createNextApiHandler({ maxBatchSize: 10 }).

maxItems option on client to match server batch limit

Use the maxItems option on httpBatchLink to ensure the client doesn't exceed the server's batch limit. This automatically splits large batches into multiple HTTP requests. The client's maxItems should be the same or lower than the server's maxBatchSize.

HTTPLinkOptions interface fields

The HTTPLinkOptions interface has the following fields: - url (required): string | URL. The URL to send requests to. - fetch (optional): typeof fetch. A ponyfill for fetch. - transformer (optional): DataTransformerOptions. A data transformer, documented at https://trpc.io/docs/server/data-transformers. - headers (optional): HTTPHeaders | ((opts: { op: Operation }) => HTTPHeaders | Promise<HTTPHeaders>). Headers to be set on outgoing requests or a callback that returns said headers, documented at https://trpc.io/docs/client/headers. - methodOverride (optional): 'POST'. Send all requests as POST requests regardless of the procedure type. The server must separately allow overriding the method, documented at https://trpc.io/docs/rpc.

httpLink usage example

import { createTRPCClient, httpLink } from '@trpc/client'; import type { AppRouter } from './server'; const client = createTRPCClient<AppRouter>({ links: [ httpLink({ url: 'http://localhost:3000', // transformer, }), ], });

HTTPHeaders type definition

HTTPHeaders is defined as Record<string, string[] | string | undefined>, allowing headers to be specified as a record with string keys and values that can be strings, arrays of strings, or undefined.

localLink onError handler parameters

The onError handler receives options including the error, operation type, path, input, and context when an error occurs during a procedure call.

localLink supports abort signals

localLink provides support for abort signals, allowing requests to be cancelled.

localLink supports queries, mutations, and subscriptions

localLink provides full support for queries, mutations, and subscriptions, with automatic error handling and transformation.

localLink is prefixed unstable_ but safe to use

localLink is prefixed with unstable_ because it is a new API, but it is safe to use in production applications.

localLink createContext receives each procedure call

The createContext function is called for each procedure call and should return a promise that resolves to the context object.

localLink use cases and recommendations

localLink is recommended for scenarios where you need direct procedure calls without HTTP overhead. For most client-side applications, httpLink or other HTTP-based links should be used instead.

localLink is a terminating link for direct procedure calls

localLink is a terminating link that allows you to make tRPC procedure calls directly in your application without going through HTTP.

localLink usage example with createTRPCClient

import { createTRPCClient, unstable_localLink } from '@trpc/client'; import type { AppRouter } from './server'; import { appRouter } from './server'; const client = createTRPCClient<AppRouter>({ links: [ unstable_localLink({ router: appRouter, createContext: async () => { // Create your context here return {}; }, onError: (opts) => { // Log errors here, similarly to how you would in an API route console.error('Error:', opts.error); }, }), ], }); This example shows how to create a tRPC client using localLink with a router, context creation function, and error handler.

localLink options interface

type LocalLinkOptions<TRouter extends AnyRouter> = { router: TRouter; createContext: () => Promise<inferRouterContext<TRouter>>; onError?: (opts: ErrorHandlerOptions<inferRouterContext<TRouter>>) => void; } & TransformerOptions<inferClientTypes<TRouter>>; Required options: router (the tRPC router instance), createContext (function that returns a promise resolving to context object). Optional options: onError (error handler called when an error occurs during procedure call), transformer (optional input/output transformers for serialization/deserialization).

loggerLink enabled option use case

The enabled option accepts a function that receives opts parameter and returns a boolean. A common pattern is to log in development and only log errors in production: enabled: (opts) => (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') || (opts.direction === 'down' && opts.result instanceof Error)

LoggerLinkOptions type definition

LoggerLinkOptions is a type with the following properties: logger (optional LogFn, custom logger function), enabled (optional EnabledFn that returns a boolean to determine whether to enable the logger, defaults to true), console (optional ConsoleEsque object used in the built-in defaultLogger), colorMode (optional string, either 'ansi', 'css', or 'none', defaults to 'ansi' for server environments or 'css' for browser environments based on typeof window === 'undefined' ? 'ansi' : 'css'), withContext (optional boolean to include context in the log, defaults to false unless colorMode is 'css').

loggerLink import and usage

loggerLink is imported from '@trpc/client' and added to the links array in createTRPCClient configuration. Example: createTRPCClient<AppRouter>({ links: [loggerLink({ enabled: (opts) => (process.env.NODE_ENV === 'development' && typeof window !== 'undefined') || (opts.direction === 'down' && opts.result instanceof Error) }), httpBatchLink({ url: 'http://localhost:3000' })] })

loggerLink purpose and behavior

The loggerLink is a client link that lets you implement a logger for your tRPC client to see what operations are queries, mutations, or subscriptions, their requests, and responses. By default, it prints a prettified log to the browser's console but allows you to customize the logging behavior and output.

httpSubscriptionLink reconnectAfterInactivityMs timeout configuration

httpSubscriptionLink supports configuring a timeout for inactivity through the reconnectAfterInactivityMs option. If no messages (including ping messages) are received within the specified timeout period, the connection will be marked as 'connecting' and automatically attempt to reconnect.

httpSubscriptionLink is a terminating link using Server-sent Events

httpSubscriptionLink is a terminating link that uses Server-sent Events (SSE) for subscriptions. SSE is a good option for real-time as it is easier than setting up a WebSockets server.

httpSubscriptionLink requires EventSource polyfill if not supported

If the client's environment does not support EventSource, an EventSource polyfill is needed. For React Native, specific compatibility instructions are required.

httpSubscriptionLink must be used with splitLink

To use httpSubscriptionLink, you must use a splitLink to explicitly route subscriptions through SSE while other operation types use different links.

Same-domain httpSubscriptionLink sends cookies automatically

When the client and server are on the same domain in a web application, cookies are sent automatically as part of the request.

Cross-domain httpSubscriptionLink requires withCredentials

When the client and server are on different domains, use withCredentials: true in eventSourceOptions to enable credential transmission for httpSubscriptionLink.

SSE maxDurationMs limits connection duration

The maxDurationMs option sets the maximum duration of a single SSE connection in milliseconds. When this duration is exceeded, the connection is ended.

httpSubscriptionLink example with basic setup

```ts import { createTRPCClient, httpBatchLink, httpSubscriptionLink, loggerLink, splitLink, } from '@trpc/client'; import type { AppRouter } from './server'; const trpcClient = createTRPCClient<AppRouter>({ links: [ loggerLink(), splitLink({ condition: (op) => op.type === 'subscription', true: httpSubscriptionLink({ url: `/api/trpc`, }), false: httpBatchLink({ url: `/api/trpc`, }), }), ], }); ``` This example shows basic httpSubscriptionLink setup with splitLink routing subscriptions to SSE and other operations to batch link.

httpSubscriptionLink example with withCredentials for cross-domain

```ts httpSubscriptionLink({ url: 'https://example.com/api/trpc', eventSourceOptions() { return { withCredentials: true, }; }, }); ``` This example shows how to enable credentials for cross-domain httpSubscriptionLink requests.

httpSubscriptionLink custom headers via EventSource ponyfill

You can ponyfill EventSource using event-source-polyfill and use the eventSourceOptions callback to populate custom headers. This is recommended for non-web environments.

httpSubscriptionLink example with EventSource ponyfill and custom headers

```ts import { createTRPCClient, httpBatchLink, httpSubscriptionLink, splitLink, } from '@trpc/client'; import { EventSourcePolyfill } from 'event-source-polyfill'; import type { AppRouter } from './server'; const trpc = createTRPCClient<AppRouter>({ links: [ splitLink({ condition: (op) => op.type === 'subscription', true: httpSubscriptionLink({ url: 'http://localhost:3000', EventSource: EventSourcePolyfill, eventSourceOptions: async ({ op }) => { const signature = await getSignature(op); return { headers: { authorization: 'Bearer supersecret', 'x-signature': signature, }, }; }, }), false: httpBatchLink({ url: 'http://localhost:3000', }), }), ], }); ``` This example shows how to use EventSourcePolyfill to add custom headers including authorization with a dynamically generated signature.

httpSubscriptionLink cannot re-execute eventSourceOptions on active connection

EventSource does not allow re-execution of eventSourceOptions() or url() options to update configuration on an active connection. This is problematic when authentication expires during a subscription.

Use retryLink with httpSubscriptionLink to update expired authentication

Use a retryLink in conjunction with httpSubscriptionLink to re-establish connections with updated configuration, including refreshed authentication details. Restarting the connection will recreate the EventSource from scratch, losing any previously tracked events.

httpSubscriptionLink example with retryLink for auth token renewal

```ts import { createTRPCClient, httpBatchLink, httpSubscriptionLink, retryLink, splitLink, } from '@trpc/client'; import { EventSourcePolyfill, EventSourcePolyfillInit, } from 'event-source-polyfill'; import type { AppRouter } from './server'; const trpc = createTRPCClient<AppRouter>({ links: [ splitLink({ condition: (op) => op.type === 'subscription', false: httpBatchLink({ url: 'http://localhost:3000', }), true: [ retryLink({ retry: (opts) => { const code = opts.error.data?.code; if (!code) { console.error('No error code found, retrying', opts); return true; } if (code === 'UNAUTHORIZED' || code === 'FORBIDDEN') { console.log('Retrying due to 401/403 error'); return true; } return false; }, }), httpSubscriptionLink({ url: async () => { return getAuthenticatedUri(); }, EventSource: EventSourcePolyfill, eventSourceOptions: async () => { const token = await auth.getOrRenewToken(); return { headers: { authorization: `Bearer ${token}`, }, }; }, }), ], }), ], }); ``` This example shows how to use retryLink with httpSubscriptionLink to handle authentication renewal on UNAUTHORIZED or FORBIDDEN errors.

httpSubscriptionLink connectionParams sent as URL query parameter

Connection params defined in httpSubscriptionLink are sent as part of the URL under the connectionParams query parameter. This is less secure than using custom headers.

httpSubscriptionLink connectionParams example

```ts const trpc = createTRPCClient<AppRouter>({ links: [ splitLink({ condition: (op) => op.type === 'subscription', true: httpSubscriptionLink({ url: 'http://localhost:3000', connectionParams: async () => { return { token: 'supersecret', }; }, }), false: httpBatchLink({ url: 'http://localhost:3000', }), }), ], }); ``` This example shows how to pass connection params that will be serialized as URL query parameters.

Server-side SSE reconnectAfterInactivityMs configuration

```ts import { initTRPC } from '@trpc/server'; export const t = initTRPC.create({ sse: { client: { reconnectAfterInactivityMs: 3_000, }, }, }); ``` This example shows how to configure client-side reconnection timeout on the server when initializing tRPC.

Give your agent this brain