A realtime multiplayer version of the boardgame Ricochet Robots
at master 3.5 kB view raw
1/** 2 * YOU PROBABLY DON'T NEED TO EDIT THIS FILE, UNLESS: 3 * 1. You want to modify request context (see Part 1). 4 * 2. You want to create a new middleware or type of procedure (see Part 3). 5 * 6 * TL;DR - This is where all the tRPC server stuff is created and plugged in. The pieces you will 7 * need to use are documented accordingly near the end. 8 */ 9import { initTRPC, TRPCError } from "@trpc/server"; 10import superjson from "superjson"; 11import { ZodError } from "zod"; 12 13import { db } from "~/server/db"; 14import { validateSessionTokenCookie } from "../auth/validate"; 15 16/** 17 * 1. CONTEXT 18 * 19 * This section defines the "contexts" that are available in the backend API. 20 * 21 * These allow you to access things when processing a request, like the database, the session, etc. 22 * 23 * This helper generates the "internals" for a tRPC context. The API handler and RSC clients each 24 * wrap this and provides the required context. 25 * 26 * @see https://trpc.io/docs/server/context 27 */ 28export const createTRPCContext = async (opts: { headers: Headers }) => { 29 return { 30 db, 31 ...opts, 32 }; 33}; 34 35/** 36 * 2. INITIALIZATION 37 * 38 * This is where the tRPC API is initialized, connecting the context and transformer. We also parse 39 * ZodErrors so that you get typesafety on the frontend if your procedure fails due to validation 40 * errors on the backend. 41 */ 42const t = initTRPC.context<typeof createTRPCContext>().create({ 43 transformer: superjson, 44 errorFormatter({ shape, error }) { 45 return { 46 ...shape, 47 data: { 48 ...shape.data, 49 zodError: 50 error.cause instanceof ZodError ? error.cause.flatten() : null, 51 }, 52 }; 53 }, 54}); 55 56/** 57 * Create a server-side caller. 58 * 59 * @see https://trpc.io/docs/server/server-side-calls 60 */ 61export const createCallerFactory = t.createCallerFactory; 62 63/** 64 * 3. ROUTER & PROCEDURE (THE IMPORTANT BIT) 65 * 66 * These are the pieces you use to build your tRPC API. You should import these a lot in the 67 * "/src/server/api/routers" directory. 68 */ 69 70/** 71 * This is how you create new routers and sub-routers in your tRPC API. 72 * 73 * @see https://trpc.io/docs/router 74 */ 75export const createTRPCRouter = t.router; 76 77/** 78 * Middleware for timing procedure execution and adding an artificial delay in development. 79 * 80 * You can remove this if you don't like it, but it can help catch unwanted waterfalls by simulating 81 * network latency that would occur in production but not in local development. 82 */ 83const timingMiddleware = t.middleware(async ({ next, path }) => { 84 const start = Date.now(); 85 86 if (t._config.isDev) { 87 // artificial delay in dev 88 const waitMs = Math.floor(Math.random() * 400) + 100; 89 await new Promise((resolve) => setTimeout(resolve, waitMs)); 90 } 91 92 const result = await next(); 93 94 const end = Date.now(); 95 console.log(`[TRPC] ${path} took ${end - start}ms to execute`); 96 97 return result; 98}); 99 100/** 101 * Public (unauthenticated) procedure 102 * 103 * This is the base piece you use to build new queries and mutations on your tRPC API. It does not 104 * guarantee that a user querying is authorized, but you can still access user session data if they 105 * are logged in. 106 */ 107export const publicProcedure = t.procedure.use(timingMiddleware); 108 109export const protectedProcedure = t.procedure.use(async function (opts) { 110 const user = await validateSessionTokenCookie(); 111 112 if (!user) { 113 throw new TRPCError({ code: "UNAUTHORIZED" }); 114 } 115 116 return opts.next({ 117 ctx: { 118 user, 119 }, 120 }); 121});