@mnigos/platform-hono
v0.2.0
Published
NestJS HTTP adapter for Hono.
Readme
@mnigos/platform-hono
NestJS HTTP adapter for Hono.
This package provides the extracted Hono adapter used by rigtch.fm. It is
designed for Bun-first NestJS applications and keeps the adapter surface small:
HonoAdapter, HonoAdapterOptions, and the NestHonoRequest request type.
Installation
bun add @mnigos/platform-hono hono @hono/node-server @nestjs/common @nestjs/core@nestjs/common, @nestjs/core, hono, and @hono/node-server are peer
dependencies.
Bootstrap
import { NestFactory } from '@nestjs/core'
import { HonoAdapter } from '@mnigos/platform-hono'
import { AppModule } from './app.module'
const adapter = new HonoAdapter()
const app = await NestFactory.create(AppModule, adapter)
await app.listen(3000)CORS
Use Nest's normal CORS API:
const adapter = new HonoAdapter()
const app = await NestFactory.create(AppModule, adapter)
app.enableCors({
origin: 'https://example.com',
})Body Parsing
Request body parsing is enabled by default unless Nest is bootstrapped with
bodyParser: false.
The adapter parses JSON, text, form, and multipart request bodies and stores the
parsed value on req.body for Nest controllers and decorators.
const app = await NestFactory.create(AppModule, new HonoAdapter(), {
bodyParser: false,
})Parser Skips
Use skipBodyParserFor for routes that need the original request stream, such
as better-auth or webhook endpoints:
const adapter = new HonoAdapter({
skipBodyParserFor: ['/api/auth', '/webhooks/stripe'],
})Path matching is segment-aware. A policy for /api/auth matches /api/auth
and /api/auth/session, but not /api/authentication.
Raw Body
When Nest enables rawBody, JSON and text bodies are read once. The adapter
stores req.rawBody and parses the same payload, avoiding a second stream read.
const app = await NestFactory.create(AppModule, new HonoAdapter(), {
rawBody: true,
})Request Size Limits
The adapter applies a default body limit of 1 MiB before parsing JSON, text, form, or multipart bodies.
Configure bodyLimit to change the global default, or set bodyLimit: false
to disable the global default:
const adapter = new HonoAdapter({
bodyLimit: 2 * 1024 * 1024,
})Use route-specific requestSizeLimits for upload-heavy paths:
const adapter = new HonoAdapter({
requestSizeLimits: [
{
path: '/api/uploads',
maxBytes: 10 * 1024 * 1024,
errorMessage: 'Upload payload too large',
},
],
})If multiple request size limits match, the longest matching path wins.
Malformed JSON and form bodies are rejected as bad requests. Payloads exceeding the configured limit are rejected as payload-too-large errors.
Proxy Trust
Forwarded client IP headers are ignored by default. This prevents direct clients
from spoofing req.ip with headers such as x-forwarded-for.
Enable trustProxy only when the application is deployed behind a trusted proxy:
const adapter = new HonoAdapter({
trustProxy: true,
})By default, trusted proxy mode considers common proxy headers including
cf-connecting-ip, x-forwarded-for, x-real-ip, forwarded, and
true-client-ip.
To restrict the accepted headers:
const adapter = new HonoAdapter({
trustProxy: {
headers: ['cf-connecting-ip'],
},
})Host headers and redirect targets remain caller-controlled HTTP input. Validate public origins and redirect destinations in application code before using them for security-sensitive flows.
Request Type
The adapter attaches Nest-compatible fields to Hono's request object. Use
NestHonoRequest when a controller needs to type @Req() access:
import { Controller, Post, Req } from '@nestjs/common'
import type { NestHonoRequest } from '@mnigos/platform-hono'
@Controller()
export class WebhookController {
@Post('/webhooks/example')
handleWebhook(@Req() req: NestHonoRequest) {
return {
body: req.body,
rawBody: req.rawBody,
}
}
}Adapter-provided request fields include body, rawBody, params, query,
headers, ip, and baseUrl.
Response Support
The adapter supports common Nest controller return values:
- JSON-serializable objects and arrays
- strings, numbers, booleans, buffers, and empty responses
Promiseand non-SSEObservablevalues resolved by NestResponseinstances from the Fetch APIStreamableFile- Node.js
Readablestreams - Web
ReadableStreamstreams @Redirect(),@Header(), and@HttpCode()@Sse()handlers returningObservable<MessageEvent>
Stream chunks must be strings, Uint8Array/Buffer, or ArrayBuffer.
Object-mode stream chunks are rejected instead of being stringified.
import { Controller, Get, Sse, StreamableFile } from '@nestjs/common'
import { createReadStream } from 'node:fs'
import { interval, map } from 'rxjs'
@Controller()
export class FilesController {
@Get('/file')
file() {
return new StreamableFile(createReadStream('report.pdf'), {
type: 'application/pdf',
disposition: 'attachment; filename="report.pdf"',
})
}
@Get('/raw-stream')
rawStream() {
return createReadStream('report.pdf')
}
@Sse('/events')
events() {
return interval(1000).pipe(map(() => ({ data: { ok: true } })))
}
}The following Nest response features are intentionally deferred:
@Render()and template/view-engine rendering- Express/Fastify-style manual response APIs via
@Res(), such asres.send(),res.json(),res.end(), orstream.pipe(res)
Compatibility
| Area | Status |
| --- | --- |
| NestJS controllers and decorators | Supported |
| Hono node server | Supported |
| JSON, text, form, and multipart bodies | Supported |
| Raw body for JSON and text | Supported |
| Controller Response, StreamableFile, Node stream, and Web stream returns | Supported |
| Nest @Sse() server-sent events | Supported |
| Static assets | Supported |
| CORS | Supported |
| oRPC | Supported |
| better-auth | Planned |
| nestjs-better-auth | Planned |
| Express/Fastify-style manual @Res() APIs | Deferred |
| Nest versioning | Unsupported |
| Nest views/templates | Unsupported |
