first commit
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
# 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<AuditEvent>`
|
||||
- `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.
|
||||
Reference in New Issue
Block a user