Skip to content

Hono

Attach auditLog.fire / fireAsync to the Hono context with trusted XFF and optional tenant resolution.

Updated View as Markdown
npm i hono
import { Hono } from 'hono';
import { AuditLogger } from 'logbun';
import {
  createAuditMiddleware,
  type LogbunHonoVariables,
} from 'logbun/plugins/hono';
import type { IAdapter } from 'logbun';

type Actions = 'course.created';

declare const adapter: IAdapter;
declare function tenantIdFromVerifiedSession(c: unknown): string | undefined;

const audit = new AuditLogger<Actions>({
  namespace: 'api',
  adapter,
  requireTenantId: true,
});
await audit.ready;

const app = new Hono<{ Variables: LogbunHonoVariables<Actions> }>();
app.use(
  '*',
  createAuditMiddleware(audit, {
    trustedProxyCount: 1,
    getTenantId: (c) => tenantIdFromVerifiedSession(c),
  }),
);

app.post('/courses', async (c) => {
  const auditLog = c.get('auditLog');
  auditLog.fire('course.created', { actorId: 'user_1', entityId: 'course_1' });
  await auditLog.fireAsync('course.created', {
    actorId: 'user_1',
    entityId: 'course_1',
  });
  return c.json({ ok: true });
});

auditLog.fire never throws. auditLog.fireAsync may reject.

Hono does not take getWaitUntil. The middleware reads c.executionCtx.waitUntil structurally when present (Workers) and wraps it so host throws cannot escape fire().

Options:

{
  trustedProxyCount?: number; // default 0
  getTenantId?: (c: Context) => string | undefined;
}

IP trust is documented on Plugins.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close