import { z } from "zod"; import { t } from "@repo/core-shared/trpc/init"; import type { IAuditLog } from "../../audit-log.interface"; import { auditProcedure } from "./procedures"; /** * Creates the audit admin tRPC router. * * The `auditLog` parameter is captured at router-creation time. Apps that * mount this router must pass the `IAuditLog` impl returned by `bindAudit`. * * @example * ```ts * const { auditLog } = bindAudit(container, { payloadConfig, sinks: ["payload", "stdout"] }); * const appRouter = t.router({ ..., audit: createAuditRouter(auditLog) }); * ``` */ export function createAuditRouter(auditLog: IAuditLog) { return t.router({ eraseSubject: auditProcedure .input( z .object({ actorId: z.string().min(1), mode: z.enum(["pseudonymize", "delete"]).default("pseudonymize"), }) .strict(), ) .mutation(async ({ input }) => { await auditLog.eraseSubject(input.actorId, input.mode); return { ok: true as const }; }), }); } /** * Convenience singleton for projects that have a single audit log instance. * Most callers should use `createAuditRouter` and pass the IAuditLog explicitly. * This export is a stub that throws at call time if auditLog has not been * provided — it exists for type inference purposes (`AuditRouter`). */ export const auditRouter = createAuditRouter( new Proxy({} as IAuditLog, { get(_target, prop) { if (prop === "then") return undefined; // not a Promise throw new Error( `auditRouter singleton used without providing an IAuditLog. ` + `Use createAuditRouter(auditLog) instead.`, ); }, }), ); export type AuditRouter = ReturnType;