Neutrino Docs
SDK Reference

@neutrino-io/hono-middleware

Shared Hono.js middleware for Neutrino Cloudflare Worker services.

Package: @neutrino-io/hono-middleware

Three small Hono utilities every Neutrino Cloudflare Worker service uses to keep request handling consistent — request-id propagation, NNO-shaped 404 envelopes, and NNO-shaped error envelopes.

import { requestId, notFound, onError } from "@neutrino-io/hono-middleware";

All three helpers expect a Hono environment with a requestId context variable:

type Env = { Variables: { requestId: string } };

The requestId() middleware sets that variable; notFound() and onError() read it to thread the same id into error envelopes. Wire requestId() first, then the rest:

import { Hono } from "hono";
import { requestId, notFound, onError } from "@neutrino-io/hono-middleware";

const app = new Hono<Env>();

app.use("*", requestId());
app.notFound(notFound());
app.onError(onError());

requestId()

Hono middleware that ensures every request has a unique id available on the context and echoes it back to the client.

function requestId<
  E extends { Variables: { requestId: string } },
>(): MiddlewareHandler<E>;

On each request the middleware:

  1. Reads the X-Request-Id header. If missing, generates a UUID v4 via crypto.randomUUID().
  2. Stores the id on the Hono context (c.set("requestId", id)).
  3. Awaits next().
  4. Echoes the id back as the X-Request-Id response header.

Downstream handlers read the id via c.get("requestId").

app.use("*", requestId());

app.get("/", (c) => {
  const id = c.get("requestId");
  return c.json({ ok: true, requestId: id });
});

notFound()

Hono NotFoundHandler that emits the canonical NNO error envelope for unmatched routes.

function notFound<
  E extends { Variables: { requestId: string } },
>(): NotFoundHandler<E>;

Returns HTTP 404 with body:

{
  "error": {
    "code": "NOT_FOUND",
    "message": "Not Found",
    "details": {},
    "requestId": "<requestId from context>"
  }
}
app.notFound(notFound());

onError()

Hono ErrorHandler that normalises every unhandled error into the NNO envelope.

function onError<
  E extends { Variables: { requestId: string } },
>(): ErrorHandler<E>;
  • For HTTPException (Hono-thrown), returns the exception's status with code: "HTTP_ERROR" and the exception's message.
  • For any other error, logs it via console.error("[onError]", err) and returns 500 with code: "INTERNAL_ERROR" and a generic message.
  • The requestId is read from the context.
app.onError(onError());

HTTPException output (e.g. a 401 thrown via throw new HTTPException(401, { message: "Invalid token" })):

{
  "error": {
    "code": "HTTP_ERROR",
    "message": "Invalid token",
    "requestId": "<requestId>"
  }
}

Unhandled error output:

{
  "error": {
    "code": "INTERNAL_ERROR",
    "message": "An unexpected error occurred",
    "requestId": "<requestId>"
  }
}

NNO error envelope

All three helpers (and every NNO service following the convention) emit the same shape:

{
  error: {
    code: string        // machine-readable code, e.g. "NOT_FOUND", "HTTP_ERROR", "INTERNAL_ERROR"
    message: string     // human-readable description
    requestId: string   // id of the failing request, threaded from context
    details?: unknown   // optional structured details (e.g. validation field errors)
  }
}

Downstream services and clients can rely on the envelope being present whenever the response is a 4xx/5xx originating from a NNO worker that wires notFound() + onError().

On this page