initialize project

This commit is contained in:
2025-04-03 12:55:12 +02:00
commit 8333cbf7be
31 changed files with 1632 additions and 0 deletions

22
src/trpc/query-client.ts Normal file
View File

@@ -0,0 +1,22 @@
import { QueryClient, defaultShouldDehydrateQuery } from '@tanstack/react-query'
import SuperJSON from 'superjson'
export const createQueryClient = () =>
new QueryClient({
defaultOptions: {
queries: {
// With SSR, we usually want to set some default staleTime
// above 0 to avoid refetching immediately on the client
staleTime: 30 * 1000,
},
dehydrate: {
serializeData: SuperJSON.serialize,
shouldDehydrateQuery: (query) =>
defaultShouldDehydrateQuery(query) ||
query.state.status === 'pending',
},
hydrate: {
deserializeData: SuperJSON.deserialize,
},
},
})

78
src/trpc/react.tsx Normal file
View File

@@ -0,0 +1,78 @@
'use client'
import { type QueryClient, QueryClientProvider } from '@tanstack/react-query'
import { httpBatchStreamLink, loggerLink } from '@trpc/client'
import { createTRPCReact } from '@trpc/react-query'
import type { inferRouterInputs, inferRouterOutputs } from '@trpc/server'
import { useState } from 'react'
import SuperJSON from 'superjson'
import type { AppRouter } from '@/server/api/root'
import { createQueryClient } from './query-client'
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
clientQueryClientSingleton ??= createQueryClient()
return clientQueryClientSingleton
}
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>
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),
}),
httpBatchStreamLink({
transformer: SuperJSON,
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://localhost:${process.env.PORT ?? 3000}`
}

30
src/trpc/server.ts Normal file
View File

@@ -0,0 +1,30 @@
import 'server-only'
import { createHydrationHelpers } from '@trpc/react-query/rsc'
import { headers } from 'next/headers'
import { cache } from 'react'
import { type AppRouter, createCaller } from '@/server/api/root'
import { createTRPCContext } from '@/server/api/trpc'
import { createQueryClient } from './query-client'
/**
* This wraps the `createTRPCContext` helper and provides the required context for the tRPC API when
* handling a tRPC call from a React Server Component.
*/
const createContext = cache(async () => {
const heads = new Headers(await headers())
heads.set('x-trpc-source', 'rsc')
return createTRPCContext({
headers: heads,
})
})
const getQueryClient = cache(createQueryClient)
const caller = createCaller(createContext)
export const { trpc: api, HydrateClient } = createHydrationHelpers<AppRouter>(
caller,
getQueryClient
)