Protocol-agnostic handlers (grant, withdraw, isGranted, getCategories) in core-consent/handlers/ call IConsent methods and return typed results. consentRouter uses a consent-specific tRPC context (userId + consentFactory) so each procedure can resolve the per-user IConsent instance at call time. Auth middleware guards all four procedures and maps UnauthenticatedError → UNAUTHORIZED via defineErrorMiddleware from core-shared (no local duplicate). 76 tests passing; new handler and router code at 100% branch coverage. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
69 lines
2.1 KiB
TypeScript
69 lines
2.1 KiB
TypeScript
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<ConsentRouterContext>().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;
|