Doc 01
Quickstart
Install to first protected endpoint in minutes. Copy-paste config with safe defaults already set — no security knobs left for you to get wrong.
Documentation
Detail is the third of our three principles — Security → Accountability → Detail. AI writes code fast; it does not write down why. Every HARDENED module ships a security design doc that explains each decision: what we chose, what we rejected, and the attack it stops. This page is a public cut of that depth.
A module is not a zip of code — it is code plus the documents that let you trust it. Six of them travel with every HARDENED purchase.
Doc 01
Install to first protected endpoint in minutes. Copy-paste config with safe defaults already set — no security knobs left for you to get wrong.
Doc 02
How the pieces fit: data flow, the state it keeps, the dependencies it needs, and where it sits in your request path.
Doc 03
Every non-obvious decision, written down — what we chose, why, and the alternative we rejected. The sample below is the real thing.
Doc 04
Every option, its default, and its safe range. Defaults are production-ready; the reference tells you when and why to move off them.
Doc 05
The threat model in plain words: what the module defends, what is out of scope, and which judgment axes are N/A — with the reason, never silence.
Doc 06
Append-only history shipped with lifetime updates. Each entry names the change and the reason, so an upgrade is never a black box.
The shape of the API, from install to a protected endpoint. Buyers get the full TypeScript source, SDK, and hardened Docker image; these snippets show how it reads.
1 · Configure once
import { RateLimiter } from "@samchil/rate-limiter";
const limiter = new RateLimiter({
store: process.env.REDIS_URL, // shared across every instance
window: "1m", // sliding, not fixed
max: 100, // per identity, per window
failOpen: true, // an outage never fails the API closed
});2 · Protect the request path
export async function middleware(req) {
const result = await limiter.check(identify(req));
if (!result.ok) return result.response; // 429 + RateLimit-* headers, ready to send
}3 · Differentiate by endpoint
limiter.rule("/api/export", { max: 10, window: "1m" }); // expensive: tighter
limiter.rule("/api/feed", { max: 600, window: "1m" }); // cheap read: looserThe heart of the doc set, and of the third principle: every decision next to the alternative it beat. This is the Rate Limiter’s real log — not marketing, the engineering record.
| Decision | Why we chose it | What we rejected |
|---|---|---|
| Sliding-window counter | The limit you configure is the limit actually enforced. | Fixed window — a caller fires a full quota at the end of one window and another at the start of the next, doubling your rate at the boundary. |
| Redis-backed state | Every instance shares one view of a caller's usage, so horizontal scaling can't quietly multiply the effective limit. | Per-process in-memory counters — N instances silently become N× the limit you set. |
| Fail-open on store loss | A limiter outage degrades to 'unprotected' and raises an alert — it never takes the API down with it. | Fail-closed — turns a cache blip into a full outage and a silent one at that. |
| Per-IP and per-user isolation | One noisy client spends only its own budget; everyone else's traffic is untouched. | A single global counter — one abuser starves every legitimate caller. |
| Standard 429 + RateLimit headers | Well-behaved clients see the limit and back off on their own, before you have to block them. | Bare 429 or custom headers — clients can't self-throttle, so retries pile on. |
| Access Control marked N/A | A rate limiter throttles traffic; deciding who is allowed in is a separate module's job. We document the gap instead of implying coverage. | Bundling half-built auth in — a defense we couldn't honestly stand behind. |
Why a rejected column at all? A security choice you can’t see the alternative to is just a claim. Naming what we turned down — and the failure mode it carried — is how a decision becomes auditable instead of asserted.
Defaults are production-ready out of the box. The reference exists for when you need to move off them — and tells you what moving costs.
| Option | Default | What it controls |
|---|---|---|
| window | "1m" | Sliding window length. The interval a caller's quota is measured over. |
| max | required | Requests allowed per identity, per window. |
| failOpen | true | On store failure, allow the request and alert — never fail the API closed. |
| identify | IP | How a caller is keyed. Swap to user ID or API key where you have one. |
| store | Redis | Shared counter backend so every instance agrees on usage. |
| rules | [] | Per-endpoint overrides — tighten an expensive write, loosen a cheap read. |
Each module’s full documentation lives with the module. Live modules are documented now; the rest arrive with the code.
Live · full docs
Sliding-window limiting with Redis-shared state, per-identity isolation, and fail-open degradation. The rationale and config above are its docs.
Read the module →
Docs with the module
Hashed key storage, scoped permissions, and zero-downtime rotation. Documentation ships when the module does.
Docs with the module
Zod-based schema validation with error masking and RFC 7807 problem details. Documentation ships when the module does.