Files
suaveplan/packages/api-stack/api/api-plugin-audit/README.md
2026-05-27 23:29:53 +01:00

6.7 KiB

@suaveplan/api-plugin-audit - Hono plugin wrapping @suaveplan/audit-logging as a write-through audit trail for @suaveplan/api. Installs a global middleware recording method/path/status/duration/response-size/request-id/principal-id/tenant-id per request, exposes auditService in ServiceRegistry, and surfaces c.get("audit") for handler-level events. Configurable redaction, sampling, and exclusion. Sink is caller-supplied (any AuditStorageAdapter); default is in-memory for dev. Server-tier — Bun + Node.

Hono plugin that wraps @suaveplan/audit-logging as a write-through audit trail for @suaveplan/api. Installs a global per-request audit middleware (method / path / status / duration / response size / request id / principal id / tenant id), exposes auditService in the host ServiceRegistry, and surfaces c.get("audit") for handler-level semantic events. Sink is caller-supplied; default is an in-memory adapter for development.

Documentation tree

  • audit-context — Builds the per-request AuditContext handle the audit middleware attaches to c.set("audit", context) before invoking…
  • context-augmentation — TypeScript module augmentation that adds the audit: AuditContext slot to Hono's ContextVariableMap. Without it, `c.…
  • error-codes — Defines the stable error-code registry for @suaveplan/api-plugin-audit and the concrete AuditPluginError class used…
    • error-codes — Defines the stable error-code registry for @suaveplan/api-plugin-audit and the concrete AuditPluginError class used…
  • middleware — Builds the global Hono middleware that records one audit event per non-excluded request through the underlying `AuditLo…
    • audit-middleware — Builds the global Hono middleware that records one audit event per non-excluded request through the underlying `AuditLo…
  • otel — Owns the OpenTelemetry instrument bundle the audit plugin emits to every request lifecycle. Resolving the instruments l…
    • instruments — Owns the OpenTelemetry instrument bundle the audit plugin emits to every request lifecycle. Resolving the instruments l…
  • plugin — Top-level factory for the audit plugin. createAuditPlugin(options) Zod-validates the caller's options at the boundary…
    • plugin — Top-level factory for the audit plugin. createAuditPlugin(options) Zod-validates the caller's options at the boundary…
  • redact — Lightweight, allocation-free-ish payload redactor used by the audit middleware to scrub secret-bearing fields from per-…
    • redact — Lightweight, allocation-free-ish payload redactor used by the audit middleware to scrub secret-bearing fields from per-…
  • schemas — Zod schema that validates AuditPluginOptions at the createAuditPlugin factory boundary and produces the resolved `A…
    • options — Zod schema that validates AuditPluginOptions at the createAuditPlugin factory boundary and produces the resolved `A…
  • audit-service — Constructs the AuditService adapter the plugin registers in ServiceRegistry under the auditService slot. The adap…
  • registry-augmentation — Declares the auditService slot on @suaveplan/api-plugin/service-registry's ServiceRegistry interface via TypeScri…
  • types — Central, runtime-free declaration of the interfaces the plugin's lifecycle, middleware, services, and context helpers d…
    • types — Central, runtime-free declaration of the interfaces the plugin's lifecycle, middleware, services, and context helpers d…

Install

bun add @suaveplan/api-plugin-audit

Quick start

import { MemoryAuditAdapter } from "@suaveplan/audit-logging";
import { createAuditPlugin } from "@suaveplan/api-plugin-audit";

const plugin = createAuditPlugin({
    sink: new MemoryAuditAdapter(),
    secretKey: process.env.AUDIT_SECRET_KEY,
    samplingRate: 1, // record every request
    excludePaths: ["/health", "/openapi.json"],
});

// Register on your @suaveplan/api PluginRegistry alongside auth/tenant/etc.

Inside 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({ ok: true });
});

Modules

Features

  • One audit event per non-excluded request, recorded through the underlying AuditLogger (chain-integrity, GDPR export, retention all inherited).
  • Configurable redaction (case-insensitive headers, exact query / body field names).
  • Head-end sampling gate with caller-supplied (or default Math.random) RNG.
  • Excluded paths skip recording but still install the audit context slot.
  • Middleware NEVER throws into the request response — sink failures are logged at warn and counted via audit.sink_failures_total.
  • auditService registered with ctx.registerService("auditService", ...) and exposed through the typed ServiceRegistry slot.
  • Hono ContextVariableMap augmented with audit: AuditContext so handlers fire explicit events without import boilerplate.
  • Four OpenTelemetry instruments: audit.requests_recorded_total{outcome,sampled}, audit.requests_excluded_total, audit.sink_failures_total, audit.middleware_duration_ms.