import { initTRPC, TRPCError } from '@trpc/server' import superjson from 'superjson' import { flatten, ValiError } from 'valibot' import { auth } from '~/server/better-auth' import { db } from '~/server/db' export const createTRPCContext = async (opts: { headers: Headers }) => { const session = await auth.api.getSession({ headers: opts.headers }) return { db, session, ...opts } } const t = initTRPC.context().create({ transformer: superjson, errorFormatter({ shape, error }) { return { ...shape, data: { ...shape.data, validationError: error.cause instanceof ValiError ? flatten(error.cause.issues) : null, }, } }, }) export const createCallerFactory = t.createCallerFactory export const createTRPCRouter = t.router const isTest = process.env.VITEST === 'true' const timingMiddleware = t.middleware(async ({ next, path }) => { const start = Date.now() if (t._config.isDev && !isTest) { const waitMs = Math.floor(Math.random() * 400) + 100 await new Promise((resolve) => setTimeout(resolve, waitMs)) } const result = await next() if (t._config.isDev && !isTest) { // biome-ignore lint/suspicious/noConsole: dev timing instrumentation console.log(`[TRPC] ${path} took ${Date.now() - start}ms to execute`) } return result }) export const publicProcedure = t.procedure.use(timingMiddleware) export const protectedProcedure = t.procedure.use(timingMiddleware).use(({ ctx, next }) => { if (!ctx.session?.user) { throw new TRPCError({ code: 'UNAUTHORIZED' }) } return next({ ctx: { session: { ...ctx.session, user: ctx.session.user }, }, }) })