From d8a17e696d49df89118602130f37b5ae8624c881 Mon Sep 17 00:00:00 2001 From: adesuwa-tech Date: Fri, 24 Jul 2026 22:07:12 +0000 Subject: [PATCH] feat: streaming audit export - mount adminAuditExportRouter in app --- src/index.ts | 2 + src/routes/admin/audit.ts | 79 +-------------------------------------- 2 files changed, 4 insertions(+), 77 deletions(-) diff --git a/src/index.ts b/src/index.ts index a42d7ff..e72a79a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -27,6 +27,7 @@ import { sessionsRouter } from "./routes/me/sessions"; import { notificationsRouter } from "./routes/notifications"; import { socialRouter } from "./routes/social"; import { adminAuditRouter } from "./routes/admin/audit"; +import { adminAuditExportRouter } from "./routes/admin/audit/export"; import { adminMarketsRouter } from "./routes/admin/markets"; import { adminSchemaVersionsRouter } from "./routes/admin/schema-versions"; import { errorHandler } from "./middleware/errorHandler"; @@ -124,6 +125,7 @@ export function createApp(): express.Express { app.use("/api/me/devices", devicesRouter); app.use("/api/me/sessions", sessionsRouter); app.use("/api/admin/audit", adminAuditRouter); + app.use("/api/admin/audit", adminAuditExportRouter); app.use("/api/admin/users", adminUsersRouter); app.use("/api/admin/feature-flags", adminFeatureFlagsRouter); app.use('/feature-flags', featureFlagsRouter); diff --git a/src/routes/admin/audit.ts b/src/routes/admin/audit.ts index 4955ed9..0c9cb5a 100644 --- a/src/routes/admin/audit.ts +++ b/src/routes/admin/audit.ts @@ -46,83 +46,8 @@ export function createAdminAuditRouter(opts: AdminAuditRouterOptions = {}): Rout router.use(requireAdmin); - // Mount search handler to clear unused variable lint error - router.get("/search", searchAuditLogsHandler); - - router.get("/", async (req, res, next) => { - try { - const parseResult = auditQuerySchema.safeParse(req.query); - if (!parseResult.success) { - throw RouteErrorFactory.validation( - parseResult.error.issues[0]?.message ?? "invalid query parameters", - ); - } - - const filters = parseResult.data; - const page = await getAuditLogs(filters); - - res.json({ - data: page.data, - nextCursor: page.nextCursor, - }); - } catch (e) { - next(e); - } - }); - - return router; -} - -export const adminAuditRouter = createAdminAuditRouter();import { Router } from "express"; -import { rateLimit } from "express-rate-limit"; -import { z } from "zod"; -import { requireAdmin } from "../../middleware/requireAdmin"; -import { getAuditLogs } from "../../repositories/auditLogRepo"; -import { RouteErrorFactory } from "../../errors"; -import { searchAuditLogsHandler } from "./audit/search"; - -export interface AdminAuditRouterOptions { - rateLimitPerMinute?: number; -} - -const auditQuerySchema = z.object({ - action: z.string().optional(), - actor: z.string().optional(), - startDate: z.string() - .datetime({ message: "startDate must be a valid ISO 8601 datetime string" }) - .transform((val) => new Date(val)) - .optional(), - endDate: z.string() - .datetime({ message: "endDate must be a valid ISO 8601 datetime string" }) - .transform((val) => new Date(val)) - .optional(), - cursor: z.string().optional(), - limit: z.string() - .regex(/^\d+$/, { message: "limit must be a positive integer" }) - .transform((val) => parseInt(val, 10)) - .optional(), -}); - -export function createAdminAuditRouter(opts: AdminAuditRouterOptions = {}): Router { - const router = Router(); - const limit = opts.rateLimitPerMinute ?? 60; - - router.use( - rateLimit({ - windowMs: 60_000, - limit, - keyGenerator: (req) => - (req.headers.authorization as string | undefined) ?? req.ip ?? "unknown", - standardHeaders: "draft-6", - legacyHeaders: false, - message: { error: { code: "rate_limit_exceeded" } }, - }), - ); - - router.use(requireAdmin); - - // Mount search handler to clear unused variable lint error - router.get("/search", searchAuditLogsHandler); + // Mount search handler (POST — parses req.body) + router.post("/search", searchAuditLogsHandler); router.get("/", async (req, res, next) => { try {