Files
skills/docs/api-stack/api/api-plugin-rate-limit/src/middleware/context-augmentation.md
2026-05-29 08:20:56 +01:00

2.2 KiB

middleware/context-augmentation — Hono context-variable augmentation

Purpose

Augments Hono's ContextVariableMap interface so handlers calling c.get("rateLimit") get a typed RateLimitDecision rather than unknown. Without this declaration downstream handlers would have to narrow the value at the call site every time.

The augmentation is global (Hono's ContextVariableMap is a single declaration-merged interface across the whole project), so loading this module via the package barrel is sufficient — consumers do not need to import it explicitly.

Features

  • Single side-effect-free module that contributes one slot to ContextVariableMap.
  • The package barrel imports this file for its side effects so the augmentation surfaces transparently.
  • The slot type is exact (RateLimitDecision), not the loose unknown Hono ships by default.

Usage: Basic

import { Hono } from "hono";
import "@suaveplan/api-plugin-rate-limit"; // side-effect import surfaces the slot

const app = new Hono();
app.get("/api/users", (c) => {
    const decision = c.get("rateLimit"); // typed RateLimitDecision
    return c.json({ remaining: decision.remaining });
});

Usage: Advanced

import { createMiddleware } from "hono/factory";
import type { RateLimitDecision } from "@suaveplan/api-plugin-rate-limit";

export const enrichResponseWithRateLimit = createMiddleware(async (c, next) => {
    await next();
    const decision: RateLimitDecision | undefined = c.get("rateLimit");
    if (decision !== undefined) {
        c.res.headers.set("X-Service-Quota", String(decision.remaining));
    }
});

API Reference

  • Module augmentation: declare module "hono" { interface ContextVariableMap { rateLimit: RateLimitDecision } }.

Implementation Notes

  • The slot is declared without ? so handlers may not read it before the middleware has run. In practice this is fine — the middleware is the only thing that writes the slot and it does so before next().
  • Adding additional slots requires editing this file and bumping the package's minor version (the augmentation is part of the public surface).
  • The augmentation file is co-located with the middleware that populates the slot so future readers find both in one place.