"use client";
import { QueryClientProvider, type QueryClient } from "@tanstack/react-query";
import { httpBatchLink, isNonJsonSerializable, loggerLink } from "@trpc/client";
import { createTRPCReact } from "@trpc/react-query";
import { useState } from "react";
import SuperJSON from "superjson";
import { createQueryClient } from "./query-client";
import type { inferRouterInputs, inferRouterOutputs, TRPCCombinedDataTransformer } from "@trpc/server";
import type { AppRouter } from "~/server/api/root";
let clientQueryClientSingleton: QueryClient | undefined = undefined;
const getQueryClient = () => {
if (typeof window === "undefined") {
// Server: always make a new query client
return createQueryClient();
}
// Browser: use singleton pattern to keep the same query client
return (clientQueryClientSingleton ??= createQueryClient());
};
export const api = createTRPCReact<AppRouter>();
/**
* Inference helper for inputs.
*
* @example type HelloInput = RouterInputs['example']['hello']
*/
export type RouterInputs = inferRouterInputs<AppRouter>;
/**
* Inference helper for outputs.
*
* @example type HelloOutput = RouterOutputs['example']['hello']
*/
export type RouterOutputs = inferRouterOutputs<AppRouter>;
// https://github.com/trpc/trpc/issues/1937#issuecomment-2557358137
export const transformer: TRPCCombinedDataTransformer = {
input: {
serialize: (obj) => {
if (isNonJsonSerializable(obj)) {
return obj;
} else {
return SuperJSON.serialize(obj);
}
},
deserialize: (obj) => {
if (isNonJsonSerializable(obj)) {
return obj;
} else {
return SuperJSON.deserialize(obj);
}
},
},
output: SuperJSON,
};
export function TRPCReactProvider(props: { children: React.ReactNode }) {
const queryClient = getQueryClient();
const [trpcClient] = useState(() =>
api.createClient({
links: [
loggerLink({
enabled: (op) =>
process.env.NODE_ENV === "development" ||
(op.direction === "down" && op.result instanceof Error),
}),
httpBatchLink({
transformer,
url: getBaseUrl() + "/api/trpc",
headers: () => {
const headers = new Headers();
headers.set("x-trpc-source", "nextjs-react");
return headers;
},
})
],
})
);
return (
<QueryClientProvider client={queryClient}>
<api.Provider
client={trpcClient}
queryClient={queryClient}
>
{props.children}
</api.Provider>
</QueryClientProvider>
);
}
function getBaseUrl() {
if (typeof window !== "undefined") return window.location.origin;
if (process.env.VERCEL_URL) return `https://${process.env.VERCEL_URL}`;
return `http://127.0.0.1:${process.env.PORT ?? 3000}`;
}