3.0 KiB
3.0 KiB
Tasks: enterprise-api-plugin-rate-limit
Change ID: enterprise-api-plugin-rate-limit
Package: @suaveplan/api-plugin-rate-limit
Target path: api/data/api-plugin-rate-limit
Prerequisite packages on Verdaccio: @suaveplan/api, @suaveplan/api-shared, @suaveplan/api-plugin-auth, @suaveplan/rate-limiter, @suaveplan/events, @suaveplan/error
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold + types + errors + events
- Create directory;
package.jsonv0.0.0; standard tooling. - Types:
RouteRateLimitOptions,RateLimitResult,RateLimitState,RateLimitPluginConfig(Zod). - Errors: 3-code union + registration. Test + doc.
- Events:
RateLimitEventMap(rate-limit:exceeded, rate-limit:reset).
2. RateLimiterService
middleware(options)— factory returning HonoMiddlewareHandler; extracts key viakeyExtractor; callscheck; on limit exceeded emitsrate-limit:exceeded, returns 429 withRetry-Afterheader.check(key, limit, windowMs)— delegates to@suaveplan/rate-limiter.reset(key)— admin; emitsrate-limit:reset.getState(key)— returns current window count + remaining.- OTel:
rate_limit.checks_total,rate_limit.exceeded_totalcounters. .test.ts+.md.
3. Middleware factory
createRateLimitMiddleware(service, options)— convenience wrapper.- Per-tenant override: if
c.get('tenantId')present, look up tenant-specific limit override from config. .test.ts+.md.
4. Admin routes
GET /admin/rate-limits/:key—requireAuth+requireRole("ADMIN").DELETE /admin/rate-limits/:key— reset;requireAuth+requireRole("ADMIN").- Route
.test.ts+.md.
5. Plugin factory + integration tests + publish
createRateLimitPlugin:definePlugin,dependencies: ["auth"].onInit: instantiateRateLimiterServicewith config; register as"rate-limiter"service.- Integration: middleware applied → 5 requests pass → 6th returns 429 → reset → pass again.
bunx turbo lint typecheck test --filter=@suaveplan/api-plugin-rate-limit— green; 100% coverage.bun scripts/publish.ts --package @suaveplan/api-plugin-rate-limit.- Archive →
openspec/archive/2026-04-24-enterprise-api-plugin-rate-limit/.