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>
55 lines
1.7 KiB
TypeScript
55 lines
1.7 KiB
TypeScript
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<typeof createAuditRouter>;
|