import { initTRPC, TRPCError } from "@trpc/server"; import type { TRPCContext } from "./trpc"; const t = initTRPC.context().create(); export const createTRPCRouter = t.router; export const publicProcedure = t.procedure; const isAuthed = t.middleware(({ ctx, next }) => { if (!ctx.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } return next({ ctx: { user: ctx.user }, }); }); export const protectedProcedure = t.procedure.use(isAuthed); const isAdmin = t.middleware(({ ctx, next }) => { if (!ctx.user) { throw new TRPCError({ code: "UNAUTHORIZED" }); } if ((ctx.user.role as string) !== "admin") { throw new TRPCError({ code: "FORBIDDEN" }); } return next({ ctx: { user: ctx.user }, }); }); export const adminProcedure = t.procedure.use(isAdmin); const rateLimitMap = new Map(); const isRateLimited = t.middleware(({ ctx, next }) => { const identifier = ctx.user?.id ?? ctx.apiKey ?? "anonymous"; const now = Date.now(); const entry = rateLimitMap.get(identifier); const limit = 100; const windowMs = 60_000; if (!entry || now > entry.resetAt) { rateLimitMap.set(identifier, { count: 1, resetAt: now + windowMs }); return next(); } if (entry.count >= limit) { throw new TRPCError({ code: "TOO_MANY_REQUESTS", message: "Rate limit exceeded", }); } entry.count++; return next(); }); export const rateLimitedProcedure = t.procedure.use(isRateLimited);