TypeScript clients and transports
Call generated operations without React and choose HTTP, WebSocket, or automatic transport selection.
Use @relkit/client when a browser, script, or application already owns its request lifecycle.
The client returns typed results and rejects on failures. React applications can use the
provider and hooks to manage loading, caching, and identity state.
Install and load your contract
In the caller package:
From this guide’s application/package root, install only its selected requirements:
bun add @opentelemetry/api@1.9.1 @relkit/client@0.8.2
Keep these owner-specific versions and the lockfile together. Runtime SDKs belong in dependencies; build/type tooling belongs in devDependencies. Installing an adapter does not supply its optional SDK peers or enable the feature’s configuration.
Use the Frontend guide to install the
development CLI and pull the public contract. Include contract.ts and client-registry.d.ts in the
caller’s TypeScript program. The generated client.ts also imports its contract; installing the
package alone cannot infer the backend’s operations.
Call a function-backed route
With the Echo route on the backend and its
contract pulled into the caller, this function sends domain input and returns { message: string }:
/** Calls the Echo contract from a TypeScript browser frontend without React or backend source imports. */
import { createClient } from "@relkit/client";
/** Sends one message over RPC using types from the caller's pulled contract.
* @param baseUrl - Public backend origin, or the frontend origin when proxying RPC.
* @param message - Nonempty message accepted by the Echo function.
* @returns The validated message output; transport and application failures reject. */
export async function echoMessage(baseUrl: string, message: string) {
const response = await fetch(new URL("/_relkit/v1/client/identity", baseUrl), {
credentials: "include",
cache: "no-store",
});
if (!response.ok) throw new Error(`Identity request failed (${response.status})`);
const identity = await response.json();
if (
!identity ||
typeof identity.identityScope !== "string" ||
typeof identity.sessionEpoch !== "string"
) {
throw new Error("The backend returned an invalid client identity");
}
const client = createClient({
baseUrl,
headers: {
"x-relkit-identity-scope": identity.identityScope,
"x-relkit-session-epoch": identity.sessionEpoch,
},
});
return client["route.post.echo"]({ message });
}
Call echoMessage(window.location.origin, "Hello from the frontend") behind a same-origin proxy,
or pass your configured backend origin. Handle the returned Promise’s rejection in your UI.
The pulled contract exposes client["route.post.echo"]. React hooks also accept the POST /echo
selector through their generated registry. The call uses /rpc and returns the function output;
it does not return an HTTP Response.
createClient configures transport; it does not perform the identity handshake. This example first
loads the current browser identity, validates its scope and session epoch, and sends them with the
mutation. The React provider manages that handshake for hooks. Server callers must forward the same
request credentials to both requests; Bun’s server context does this for you.
If the identity changes between requests, surface the rejection and reconcile the outcome before
submitting again. Do not bypass the identity headers or automatically retry a write.
Choose a transport
All three factories are exported from @relkit/client and use the same generated contract:
| Factory | Use it for | Configuration and behavior |
|---|---|---|
createClient |
Finite HTTP calls and supported HTTP streams | baseUrl, request-time headers, credentials, and an optional fetch. |
createWebSocketClient |
A backend with WebSocket RPC enabled | baseUrl, an optional WebSocket constructor, and establishmentTimeoutMs. Connection establishment is lazy. |
createAutoClient |
WebSocket preference with HTTP fallback | Combines the transport options. Fallback applies to connection establishment, not replay of an accepted operation. |
Pass the backend origin without appending /rpc. A custom transport still needs the backend’s
matching configuration and authentication. Use HTTP streaming for
stream contracts, and client stream hooks when React owns them.
headers may be a header collection or an asynchronous provider evaluated for future requests.
Use request-scoped credentials for server callers. Browser requests include credentials by default;
separate origins need matching cookie and CORS configuration.
Add query utilities or server tracing
| Entry point | API | Owner |
|---|---|---|
@relkit/client/tanstack-query |
createTanstackQueryUtils |
Query options and cache integration |
@relkit/client/server |
createServerClient |
Bun server calls and tracing |
@relkit/client/server/tanstack-query |
createRelkitServerContext |
Request-scoped hydration |
@relkit/client/jobs |
watchJobRun, watchJobStream |
Accepted job runs |
The server leaves are Bun-only exports. Use the base createClient in other server runtimes.
Query integration is opt-in and has its own peer installation.
Handle errors and resource lifetimes
Catch ORPCError for RPC failures and inspect its code and data.
Do not treat a missing response to a write as proof that the write failed. Follow
uncertain-outcome recovery before resubmitting.
Pass cancellation signals to calls that need them, finish or cancel stream iteration, and dispose job watchers when their owner closes. A reconnect resumes observation; it is not permission to repeat a mutation. Generated clients explains how route policy, REST mapping, and RPC input differ.