Skip to content

[bug] useLogger()/context log typed as RequestLogger makes .audit optional, though createRequestLogger returns AuditableLogger #389

Description

@39hn

evlog version

2.19.1

Runtime & OS

Node 24.13.0, macOS

Framework / integration

All integrations (Hono shown below, but Next.js, Nitro, Nuxt, SvelteKit, Elysia, Express, Fastify are all affected identically).

Adapter or drain (optional)

N/A — compile-time typing issue.

Description

createRequestLogger() returns AuditableLogger<T>, where audit is required (packages/evlog/src/logger.ts:1028, audit.ts:180). But the loggers that integrations expose to user code — useLogger() and per-request context vars — are typed as RequestLogger<T>, where audit is optional (types.ts:761). The runtime value is always the AuditableLogger, so .audit is in fact always present, yet TypeScript infers it as possibly undefined.

Affected surfaces (all typed RequestLogger): Hono EvlogVariables (hono/index.ts:23), and useLogger() for Next.js (next/storage.ts:21), Nitro (nitro-v3/useLogger.ts:20), generic server (runtime/server/useLogger.ts:35), Elysia (elysia/index.ts:32), Express/Fastify (shared/storage.ts:16), plus Request.log (express/index.ts:16) and H3EventContext.log (types.ts:923).

Expected behavior

The logger exposed via useLogger() / c.get('log') / req.log / event.context.log should be typed as AuditableLogger<T>, so .audit(…) type-checks without optional chaining or !.

Actual behavior

audit is inferred as optional, so calling it errors:

const log = c.get('log') // typed RequestLogger
log.audit({ action: 'users.list', outcome: 'success' })
//  ~~~~~ Cannot invoke an object which is possibly 'undefined'. ts(2722)

Workaround required today: log.audit?.(…) or log.audit!(…).

Reproduction

import { Hono } from 'hono'
import { evlog, type EvlogVariables } from 'evlog/hono'

const app = new Hono<EvlogVariables>()
app.use(evlog())

app.get('/api/users', (c) => {
  const log = c.get('log')
  log.audit({ action: 'users.list', outcome: 'success' }) // ❌ ts(2722)
  return c.json({ users: [] })
})

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions