Files
agentic-dev/packages/core-audit/src/integrations/api/procedures.ts
Danijel Martinek 131efd5d2f feat(core-audit): admin tRPC procedure for eraseSubject
Adds auditProcedure (adminOnly middleware + defineErrorMiddleware([])) in
core-audit/src/integrations/api/procedures.ts. Adds createAuditRouter that
captures an IAuditLog and exposes a single eraseSubject mutation with zod
input validation. Non-admins receive FORBIDDEN. Barrel re-exports
pseudonymize, createAuditErasureHook, createAuditRouter, auditRouter,
AuditRouter, auditProcedure, AdminTrpcUser. Adds AUDIT_PSEUDONYM_SALT to
turbo.json globalEnv to clear lint warnings.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 16:25:09 +02:00

44 lines
1.4 KiB
TypeScript

import { TRPCError } from "@trpc/server";
import { t } from "@repo/core-shared/trpc/init";
import { defineErrorMiddleware } from "@repo/core-shared/trpc/define-error-middleware";
/**
* The minimum user shape that the adminOnly middleware expects to find on `ctx`.
* Apps must include this field when creating their tRPC context for requests
* that may reach admin procedures. Unauthenticated requests leave `user`
* undefined, which the middleware treats as non-admin.
*/
export type AdminTrpcUser = {
roles: string[];
};
/**
* Middleware that blocks non-admin callers.
*
* Reads `ctx.user?.roles` from the tRPC context. Throws FORBIDDEN if the
* user is absent or lacks the "admin" role. Apps that mount the auditRouter
* must set `ctx.user` with the authenticated user's roles.
*/
const adminOnly = t.middleware(({ ctx, next }) => {
const user = (ctx as { user?: AdminTrpcUser }).user;
if (!user?.roles.includes("admin")) {
throw new TRPCError({
code: "FORBIDDEN",
message: "Admin role required",
});
}
return next({ ctx: { ...ctx, user } });
});
/**
* Base procedure for all audit admin routes.
*
* - `adminOnly` middleware gates every mutation/query.
* - `defineErrorMiddleware([])` — no audit-specific domain errors need tRPC
* mapping; the FORBIDDEN thrown by `adminOnly` is a plain TRPCError and
* propagates unchanged.
*/
export const auditProcedure = t.procedure
.use(adminOnly)
.use(defineErrorMiddleware([]));