UNPKG

kitcn

Version:

kitcn - React Query integration and CLI tools for Convex

117 lines (91 loc) 2.76 kB
## 8. Framework-Specific Setup ## 8.A Next.js App Router ### 8.A.1 Server caller + auth utilities **Create:** `src/lib/convex/server.ts` ```ts import { api } from "@convex/api"; import { convexBetterAuth } from "kitcn/auth/nextjs"; export const { createContext, createCaller, handler } = convexBetterAuth({ api, convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_URL!, }); ``` ### 8.A.2 Auth API route **Create:** `src/app/api/auth/[...all]/route.ts` ```ts import { handler } from "@/lib/convex/server"; export const { GET, POST } = handler; ``` ### 8.A.3 RSC helpers **Create:** `src/lib/convex/rsc.tsx` ```tsx import "server-only"; import { api } from "@convex/api"; import type { FetchQueryOptions } from "@tanstack/react-query"; import { dehydrate, HydrationBoundary, QueryClient, } from "@tanstack/react-query"; import { createServerCRPCProxy, getServerQueryClientOptions, } from "kitcn/rsc"; import { headers } from "next/headers"; import { cache } from "react"; import { hydrationConfig } from "./query-client"; import { createCaller, createContext } from "./server"; const createRSCContext = cache(async () => createContext({ headers: await headers() }) ); export const caller = createCaller(createRSCContext); export const crpc = createServerCRPCProxy({ api }); function createServerQueryClient() { return new QueryClient({ defaultOptions: { ...hydrationConfig, ...getServerQueryClientOptions({ getToken: caller.getToken, convexSiteUrl: process.env.NEXT_PUBLIC_CONVEX_SITE_URL!, }), }, }); } export const getQueryClient = cache(createServerQueryClient); export function prefetch<T extends { queryKey: readonly unknown[] }>( queryOptions: T ): void { void getQueryClient().prefetchQuery(queryOptions); } export function preloadQuery< TQueryFnData = unknown, TError = Error, TData = TQueryFnData, TQueryKey extends readonly unknown[] = readonly unknown[], >( options: FetchQueryOptions<TQueryFnData, TError, TData, TQueryKey> ): Promise<TData> { return getQueryClient().fetchQuery(options); } export function HydrateClient({ children }: { children: React.ReactNode }) { const queryClient = getQueryClient(); const dehydratedState = dehydrate(queryClient); return ( <HydrationBoundary state={dehydratedState}>{children}</HydrationBoundary> ); } ``` ### 8.A.4 Pass server token to provider ```tsx // app/(app)/layout.tsx import { AppConvexProvider } from "@/lib/convex/convex-provider"; import { caller } from "@/lib/convex/rsc"; export default async function AppLayout({ children, }: { children: React.ReactNode; }) { const token = await caller.getToken(); return <AppConvexProvider token={token}>{children}</AppConvexProvider>; } ```