{"id":47783986,"url":"https://github.com/araan-sheikh/tumull-shield","last_synced_at":"2026-04-03T14:04:43.280Z","repository":{"id":342951329,"uuid":"1168394195","full_name":"Araan-Sheikh/tumull-shield","owner":"Araan-Sheikh","description":"Drop-in API rate limiting \u0026 DDoS protection for Node.js/Next.js","archived":false,"fork":false,"pushed_at":"2026-03-08T07:22:07.000Z","size":124,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-08T10:27:19.629Z","etag":null,"topics":["ddos","express","fastify","hono","middleware","nextjs","nodejs","rate-limiting","security","typescript"],"latest_commit_sha":null,"homepage":"https://tumull.in/shield","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Araan-Sheikh.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-02-27T10:37:31.000Z","updated_at":"2026-03-08T07:22:00.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/Araan-Sheikh/tumull-shield","commit_stats":null,"previous_names":["araan-sheikh/tumull-shield"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/Araan-Sheikh/tumull-shield","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Araan-Sheikh%2Ftumull-shield","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Araan-Sheikh%2Ftumull-shield/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Araan-Sheikh%2Ftumull-shield/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Araan-Sheikh%2Ftumull-shield/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Araan-Sheikh","download_url":"https://codeload.github.com/Araan-Sheikh/tumull-shield/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Araan-Sheikh%2Ftumull-shield/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31355884,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-03T08:03:20.796Z","status":"ssl_error","status_checked_at":"2026-04-03T08:00:37.834Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ddos","express","fastify","hono","middleware","nextjs","nodejs","rate-limiting","security","typescript"],"created_at":"2026-04-03T14:04:42.257Z","updated_at":"2026-04-03T14:04:43.267Z","avatar_url":"https://github.com/Araan-Sheikh.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @tumull/shield\n\nRate limiting, bot detection, and brute force protection for Node.js apps. Works with Next.js, Express, Fastify, Hono, or plain `http`. No external dependencies in the core.\n\n[![npm](https://img.shields.io/npm/v/@tumull/shield)](https://npmjs.com/package/@tumull/shield) [![downloads](https://img.shields.io/npm/dm/@tumull/shield)](https://npmjs.com/package/@tumull/shield) [![bundle](https://img.shields.io/bundlephobia/minzip/@tumull/shield)](https://bundlephobia.com/package/@tumull/shield) [![license](https://img.shields.io/npm/l/@tumull/shield)](./LICENSE) [![tests](https://github.com/Araan-Sheikh/tumull-shield/actions/workflows/ci.yml/badge.svg)](https://github.com/Araan-Sheikh/tumull-shield/actions) [![release](https://img.shields.io/github/v/release/Araan-Sheikh/tumull-shield)](https://github.com/Araan-Sheikh/tumull-shield/releases/latest)\n\n---\n\n## Why?\n\nMost rate limiting libs are either too simple (fixed window, no bot detection) or tied to a paid service. Shield gives you sliding window, token bucket, bot detection, brute force protection, and per-route config — all in one package, for free, with zero lock-in.\n\n## Install\n\n```bash\nnpm install @tumull/shield\n```\n\n## Usage\n\n### Next.js\n\n```ts\n// middleware.ts\nimport { shield } from '@tumull/shield'\n\nexport default shield({\n  limit: 100,\n  window: '1m',\n})\n\nexport const config = {\n  matcher: '/api/:path*',\n}\n```\n\nThat's basically it. Your API routes are rate-limited now.\n\n### Express\n\n```ts\nimport express from 'express'\nimport { shieldExpress } from '@tumull/shield'\n\nconst app = express()\napp.use(shieldExpress({ limit: 100, window: '1m' }))\n```\n\n### Fastify\n\n```ts\nimport Fastify from 'fastify'\nimport { shieldFastify } from '@tumull/shield'\n\nconst app = Fastify()\napp.register(shieldFastify, { limit: 100, window: '1m' })\n```\n\n### Hono\n\n```ts\nimport { Hono } from 'hono'\nimport { shieldHono } from '@tumull/shield'\n\nconst app = new Hono()\napp.use('*', shieldHono({ limit: 100, window: '1m' }))\n```\n\n### Node.js HTTP\n\n```ts\nimport http from 'node:http'\nimport { shieldNode } from '@tumull/shield'\n\nconst limiter = shieldNode({ limit: 100, window: '1m' })\n\nhttp\n  .createServer(async (req, res) =\u003e {\n    if (await limiter(req, res)) return // blocked\n    res.writeHead(200)\n    res.end('ok')\n  })\n  .listen(3000)\n```\n\n## Config\n\n```ts\nshield({\n  limit: 100, // requests per window\n  window: '1m', // \"30s\", \"1m\", \"5m\", \"1h\", \"1d\"\n  block: '15m', // how long to block after exceeding limit\n  algorithm: 'sliding-window', // or 'fixed-window', 'token-bucket'\n\n  // different limits for different routes\n  routes: {\n    '/api/auth/login': { limit: 5, window: '5m', block: '30m' },\n    '/api/public/*': { limit: 500, window: '1m' },\n    '/api/private/*': { allowlistGeo: ['US', 'CA'] },\n    '/api/webhook/*': { skip: true },\n  },\n\n  // custom key (default: client IP)\n  key: (req) =\u003e req.headers.get('x-api-key') ?? extractIP(req),\n\n  store: 'memory', // default. also supports Redis, Upstash\n  botDetection: true,\n  blockBots: ['scrapy', 'curl'],\n  allowlist: ['127.0.0.1'],\n  // country-level controls (ISO codes)\n  allowlistGeo: ['US', 'CA'],\n  blocklistGeo: ['RU'],\n  wafEnabled: true,\n  wafRules: [\n    { target: 'query', operator: 'regex', value: 'union\\\\s*select', flags: 'i' },\n    { target: 'path', value: '/admin' },\n  ],\n  blocklist: [],\n  headers: true, // X-RateLimit-* headers\n\n  onLimit: (req, retryAfter) =\u003e\n    new Response(JSON.stringify({ error: 'Slow down' }), { status: 429 }),\n})\n```\n\nFull config reference → [docs/configuration.md](./docs/configuration.md)\n\n## Stores\n\n**Memory** (default) — no setup, works everywhere. LRU eviction keeps memory bounded.\n\n```ts\nimport { shield, MemoryStore } from '@tumull/shield'\nshield({ store: new MemoryStore({ maxSize: 10_000 }) })\n```\n\n**Redis** — for multi-instance / production setups.\n\n```ts\nimport { RedisStore } from '@tumull/shield/stores/redis'\nimport Redis from 'ioredis'\n\nshield({ store: new RedisStore({ client: new Redis(process.env.REDIS_URL) }) })\n```\n\n**Upstash** — HTTP-based, works on the edge (Vercel Edge, Cloudflare Workers).\n\n```ts\nimport { UpstashStore } from '@tumull/shield/stores/upstash'\n\nshield({\n  store: new UpstashStore({\n    url: process.env.UPSTASH_REDIS_URL!,\n    token: process.env.UPSTASH_REDIS_TOKEN!,\n  }),\n})\n```\n\nMore details → [docs/stores.md](./docs/stores.md)\n\n## Algorithms\n\n| Algorithm        | What it does                                  | Good for            |\n| ---------------- | --------------------------------------------- | ------------------- |\n| `sliding-window` | Weighted average of current + previous window | Most apps (default) |\n| `fixed-window`   | Simple counter, resets on interval            | High throughput     |\n| `token-bucket`   | Tokens refill at constant rate                | Bursty traffic      |\n\nMore details → [docs/algorithms.md](./docs/algorithms.md)\n\n## Response headers\n\nWhen `headers: true` (default):\n\n```\nX-RateLimit-Limit: 100\nX-RateLimit-Remaining: 73\nX-RateLimit-Reset: 1708934400\n```\n\nWhen blocked → `429 Too Many Requests` with `Retry-After` header.\n\n## How it compares\n\n|                    | Shield | express-rate-limit | @upstash/ratelimit | Arcjet   |\n| ------------------ | ------ | ------------------ | ------------------ | -------- |\n| Next.js middleware | ✅     | ❌                 | ✅                 | ✅       |\n| Edge runtime       | ✅     | ❌                 | ✅                 | ✅       |\n| Zero deps          | ✅     | ✅                 | ❌                 | ❌       |\n| Sliding window     | ✅     | ❌                 | ✅                 | ✅       |\n| Bot detection      | ✅     | ❌                 | ❌                 | ✅       |\n| Brute force        | ✅     | ❌                 | ❌                 | ✅       |\n| Per-route config   | ✅     | manual             | ❌                 | ✅       |\n| Free               | ✅     | ✅                 | freemium           | freemium |\n\n## Docs\n\n- [Getting started](./docs/getting-started.md)\n- [Configuration](./docs/configuration.md)\n- [Algorithms](./docs/algorithms.md)\n- [Stores](./docs/stores.md)\n- [Framework guides](./docs/frameworks.md)\n- [Bot detection](./docs/bot-detection.md)\n- [Brute force protection](./docs/brute-force.md)\n- [Migration from other libs](./docs/migration.md)\n\n## Contributing\n\nSee [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## License\n\nMIT — [TUMULL I.N.C.](https://github.com/Araan-Sheikh)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faraan-sheikh%2Ftumull-shield","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faraan-sheikh%2Ftumull-shield","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faraan-sheikh%2Ftumull-shield/lists"}