import { initTRPC } from "@trpc/server"; import { z } from "zod"; import { defineErrorMiddleware } from "@repo/core-shared/trpc/define-error-middleware"; import type { ConsentFactory } from "./di/bind-production"; import { UnauthenticatedError } from "./entities/errors/consent"; import { grantHandler, grantHandlerInputSchema, } from "./handlers/grant.handler"; import { withdrawHandler, withdrawHandlerInputSchema, } from "./handlers/withdraw.handler"; import { isGrantedHandler, isGrantedHandlerInputSchema, } from "./handlers/is-granted.handler"; import { getCategoriesHandler } from "./handlers/get-categories.handler"; /** tRPC context expected by the consent router. */ export type ConsentRouterContext = { /** Authenticated user id. Absent → procedures throw UNAUTHORIZED. */ userId?: string; /** Per-user consent factory (provided by the app binder). */ consentFactory: ConsentFactory; }; const tc = initTRPC.context().create(); const consentProcedure = tc.procedure .use(defineErrorMiddleware([[UnauthenticatedError, "UNAUTHORIZED"]])) .use(async ({ ctx, next }) => { if (!ctx.userId) throw new UnauthenticatedError(); return next(); }); export const consentRouter = tc.router({ grant: consentProcedure .input(grantHandlerInputSchema) .mutation(async ({ ctx, input }) => { const consent = await ctx.consentFactory(ctx.userId!); return grantHandler(consent, input); }), withdraw: consentProcedure .input(withdrawHandlerInputSchema) .mutation(async ({ ctx, input }) => { const consent = await ctx.consentFactory(ctx.userId!); return withdrawHandler(consent, input); }), isGranted: consentProcedure .input(isGrantedHandlerInputSchema) .query(async ({ ctx, input }) => { const consent = await ctx.consentFactory(ctx.userId!); return isGrantedHandler(consent, input); }), getCategories: consentProcedure .input(z.object({}).strict()) .query(async ({ ctx }) => { const consent = await ctx.consentFactory(ctx.userId!); return getCategoriesHandler(consent); }), }); export type ConsentRouter = typeof consentRouter;