import { z } from "zod"; import { createTRPCRouter, adminProcedure } from "../trpc.js"; import { createAuditEntry } from "../lib/audit.js"; import { buildWebhookCreateData, buildWebhookUpdateData, createWebhookInputSchema, loadWebhookOrThrow, sendWebhookTestRequest, updateWebhookInputSchema, } from "./webhook-support.js"; export const webhookRouter = createTRPCRouter({ /** List all webhooks. */ list: adminProcedure.query(async ({ ctx }) => { return ctx.db.webhook.findMany({ orderBy: { createdAt: "desc" }, }); }), /** Get a single webhook by ID. */ getById: adminProcedure .input(z.object({ id: z.string() })) .query(async ({ ctx, input }) => loadWebhookOrThrow(ctx.db, input.id)), /** Create a new webhook. */ create: adminProcedure .input(createWebhookInputSchema) .mutation(async ({ ctx, input }) => { const webhook = await ctx.db.webhook.create({ data: buildWebhookCreateData(input), }); void createAuditEntry({ db: ctx.db, entityType: "Webhook", entityId: webhook.id, entityName: webhook.name, action: "CREATE", userId: ctx.dbUser?.id, after: webhook as unknown as Record, source: "ui", }); return webhook; }), /** Update an existing webhook. */ update: adminProcedure .input( z.object({ id: z.string(), data: updateWebhookInputSchema, }), ) .mutation(async ({ ctx, input }) => { const existing = await loadWebhookOrThrow(ctx.db, input.id); const updated = await ctx.db.webhook.update({ where: { id: input.id }, data: buildWebhookUpdateData(input.data), }); void createAuditEntry({ db: ctx.db, entityType: "Webhook", entityId: input.id, entityName: updated.name, action: "UPDATE", userId: ctx.dbUser?.id, before: existing as unknown as Record, after: updated as unknown as Record, source: "ui", }); return updated; }), /** Delete a webhook. */ delete: adminProcedure .input(z.object({ id: z.string() })) .mutation(async ({ ctx, input }) => { const existing = await loadWebhookOrThrow(ctx.db, input.id); await ctx.db.webhook.delete({ where: { id: input.id } }); void createAuditEntry({ db: ctx.db, entityType: "Webhook", entityId: input.id, entityName: existing.name, action: "DELETE", userId: ctx.dbUser?.id, before: existing as unknown as Record, source: "ui", }); }), /** Send a test payload to a webhook URL. */ test: adminProcedure .input(z.object({ id: z.string() })) .mutation(async ({ ctx, input }) => { const wh = await loadWebhookOrThrow(ctx.db, input.id); const result = await sendWebhookTestRequest(wh); void createAuditEntry({ db: ctx.db, entityType: "Webhook", entityId: wh.id, entityName: wh.name, action: "UPDATE", userId: ctx.dbUser?.id, summary: `Tested webhook (result: ${result.success ? "success" : "failed"})`, metadata: result as unknown as Record, source: "ui", }); return result; }), });