# context/audit-context ## Purpose Builds the per-request `AuditContext` handle the audit middleware attaches to `c.set("audit", context)` before invoking `next()`. Handlers call `c.get("audit").log({...})` to fire explicit, semantic audit events alongside the implicit per-request audit that the middleware writes. This is the public extension point for application code — instead of importing `auditService` and threading it through every route, handlers reach into the Hono context. The two-method surface (`log` + `getLogger`) is intentionally small so handler code stays focused on the event payload rather than the plumbing. The same underlying `AuditLogger` instance is reused across every request — there is one logger per app, not one per request — so chain-integrity links hold across handler-level and middleware-level events. ## Features - Stable two-method surface (`log`, `getLogger`). - Hono `ContextVariableMap` augmentation declared in `./context-augmentation.ts` so `c.get("audit")` types as `AuditContext` (not `unknown`). - Zero per-request allocation beyond the lightweight wrapper object (no closures over the request, so the object can be cached if needed). ## Usage: Basic ```ts // In a route handler: app.post("/users/:id/delete", async (c) => { const audit = c.get("audit"); await audit.log({ type: "user.deleted", severity: "warning", actor: { userId: c.get("user")?.id }, target: { type: "user", id: c.req.param("id") }, }); return c.json({ deleted: true }); }); ``` ## Usage: Advanced ```ts // Reach the underlying logger for advanced ops: app.get("/admin/audit-chain/verify", async (c) => { const logger = c.get("audit").getLogger(); const events = await logger.query({ limit: 1000, order: "asc" }); const verdict = await logger.verifyChainIntegrity(events); return c.json(verdict); }); ``` ## API Reference - `createAuditContext(deps: { logger: AuditLogger }): AuditContext` - `log(event)` → `Promise` - `getLogger()` → `AuditLogger` ## Implementation Notes `AuditContext` does not carry the request, the principal, or the tenant. Handlers fill `actor.userId`, `actor.sessionId`, `tenantId`, and so on from `c.get("user")` / `c.get("tenant")` themselves. The middleware's per-request event populates those fields automatically; handler-level events stay explicit because the handler knows the semantic of the event (which user is the actor versus the target) better than the middleware does.