1"use client";
2
3import { QueryClientProvider, type QueryClient } from "@tanstack/react-query";
4import { httpBatchStreamLink, loggerLink } from "@trpc/client";
5import { createTRPCReact } from "@trpc/react-query";
6import { type inferRouterInputs, type inferRouterOutputs } from "@trpc/server";
7import { useState } from "react";
8import SuperJSON from "superjson";
9
10import { type AppRouter } from "~/server/api/root";
11import { createQueryClient } from "./query-client";
12
13let clientQueryClientSingleton: QueryClient | undefined = undefined;
14const getQueryClient = () => {
15 if (typeof window === "undefined") {
16 // Server: always make a new query client
17 return createQueryClient();
18 }
19 // Browser: use singleton pattern to keep the same query client
20 clientQueryClientSingleton ??= createQueryClient();
21
22 return clientQueryClientSingleton;
23};
24
25export const api = createTRPCReact<AppRouter>();
26
27/**
28 * Inference helper for inputs.
29 *
30 * @example type HelloInput = RouterInputs['example']['hello']
31 */
32export type RouterInputs = inferRouterInputs<AppRouter>;
33
34/**
35 * Inference helper for outputs.
36 *
37 * @example type HelloOutput = RouterOutputs['example']['hello']
38 */
39export type RouterOutputs = inferRouterOutputs<AppRouter>;
40
41export function TRPCReactProvider(props: { children: React.ReactNode }) {
42 const queryClient = getQueryClient();
43
44 const [trpcClient] = useState(() =>
45 api.createClient({
46 links: [
47 loggerLink({
48 enabled: (op) =>
49 process.env.NODE_ENV === "development" ||
50 (op.direction === "down" && op.result instanceof Error),
51 }),
52 httpBatchStreamLink({
53 transformer: SuperJSON,
54 url: getBaseUrl() + "/api/trpc",
55 headers: () => {
56 const headers = new Headers();
57 headers.set("x-trpc-source", "nextjs-react");
58 return headers;
59 },
60 }),
61 ],
62 }),
63 );
64
65 return (
66 <QueryClientProvider client={queryClient}>
67 <api.Provider client={trpcClient} queryClient={queryClient}>
68 {props.children}
69 </api.Provider>
70 </QueryClientProvider>
71 );
72}
73
74function getBaseUrl() {
75 if (typeof window !== "undefined") return window.location.origin;
76 if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
77 return `http://localhost:${process.env.PORT ?? 3000}`;
78}