Created
October 24, 2025 09:22
-
-
Save augiwan/95f533556fab39443119a36466f7d32d to your computer and use it in GitHub Desktop.
Fixes better-t-stack orpc implementation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/apps/web/src/utils/orpc.ts b/apps/web/src/utils/orpc.ts | |
| index d369d41..c5dc202 100644 | |
| --- a/apps/web/src/utils/orpc.ts | |
| +++ b/apps/web/src/utils/orpc.ts | |
| @@ -1,13 +1,11 @@ | |
| import { createORPCClient } from "@orpc/client"; | |
| import { RPCLink } from "@orpc/client/fetch"; | |
| import { createTanstackQueryUtils } from "@orpc/tanstack-query"; | |
| -import { QueryCache, QueryClient } from "@tanstack/react-query"; | |
| -import { toast } from "sonner"; | |
| -import { createRouterClient } from "@orpc/server"; | |
| import type { RouterClient } from "@orpc/server"; | |
| +import type { AppRouter } from "@myapp/api/routers/index"; | |
| import { createIsomorphicFn } from "@tanstack/react-start"; | |
| -import { appRouter } from "@myapp/api/routers/index"; | |
| -import { createContext } from "@myapp/api/context"; | |
| +import { QueryCache, QueryClient } from "@tanstack/react-query"; | |
| +import { toast } from "sonner"; | |
| export const queryClient = new QueryClient({ | |
| queryCache: new QueryCache({ | |
| @@ -25,14 +23,27 @@ export const queryClient = new QueryClient({ | |
| }); | |
| const getORPCClient = createIsomorphicFn() | |
| - .server(() => | |
| - createRouterClient(appRouter, { | |
| - context: async ({ req }) => { | |
| - return createContext({ req }); | |
| + .server((ctx = {} as { req?: Request }): RouterClient<AppRouter> => { | |
| + const requestHeaders = ctx.req ? new Headers(ctx.req.headers) : undefined; | |
| + | |
| + const link = new RPCLink({ | |
| + url: `${import.meta.env.VITE_SERVER_URL}/rpc`, | |
| + fetch(url, options) { | |
| + const mergedHeaders = new Headers(options?.headers); | |
| + requestHeaders?.forEach((value, key) => { | |
| + mergedHeaders.set(key, value); | |
| + }); | |
| + return fetch(url, { | |
| + ...options, | |
| + credentials: "include", | |
| + headers: mergedHeaders, | |
| + }); | |
| }, | |
| - }), | |
| - ) | |
| - .client((): RouterClient<typeof appRouter> => { | |
| + }); | |
| + | |
| + return createORPCClient(link) as RouterClient<AppRouter>; | |
| + }) | |
| + .client((): RouterClient<AppRouter> => { | |
| const link = new RPCLink({ | |
| url: `${import.meta.env.VITE_SERVER_URL}/rpc`, | |
| fetch(url, options) { | |
| @@ -43,9 +54,9 @@ const getORPCClient = createIsomorphicFn() | |
| }, | |
| }); | |
| - return createORPCClient(link); | |
| + return createORPCClient(link) as RouterClient<AppRouter>; | |
| }); | |
| -export const client: RouterClient<typeof appRouter> = getORPCClient(); | |
| +export const client: RouterClient<AppRouter> = getORPCClient(); | |
| export const orpc = createTanstackQueryUtils(client); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Whats happening here:
Previously the server-side
getORPCClientwas directly instantiating an in-memory router client usingThis meant server code executed RPC handlers locally without making network calls.
The patch removes
createRouterClientandappRouterimports and replaces the server logic with an actualRPCLinkpointing to${VITE_SERVER_URL}/rpc, same as the client side. Effectively, server RPC calls are no longer “short-circuited”; they now hit the Hono RPC endpoint just like the browser.It propagates incoming request headers to the RPC call:
Then merges them into the fetch call. Useful for forwarding authentication cookies, sessions, or other headers when doing SSR/loader calls.
Both client and server now use the same
createORPCClient(link)setup, typed asRouterClient<AppRouter>. Type safety remains, but no longer requires importing the router directly on the frontend.Context creation on the server (e.g.
createContext({ req })) is removed here, since the actual API server will handle it.The
export const clienttyping is updated fromto
so the web app depends only on shared type definitions, not implementation.
Why this is better:
A few points to keep in mind (but the current trpc implementation also does this):
createRouterClientfor certain dev shortcuts, those are gone.PS: Re-formatted with AI