Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

Build the rate limiter on the new CounterStore, so limits hold across server instances

Geschlossen
#245 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

@abelzach arbeitet bereits daran.

Seit 21.10.2026.

  • #274 von @abelzach — gemerged

Bewertung

Schwierigkeit
3/5
Geschätzter Aufwand
1-2 Tage
Anfängerfreundlichkeit
83/100
Issue-Typ
Feature
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
node.js, typescript
Bereich
backend, databases

Rechercherichtung

Read packages/core/src/storage/types.ts for the CounterStore contract, then review packages/server/src/rate-limit.ts and its tests for existing behavior. Implement the algorithm in packages/core/src/limits/rate-limit.ts and add fake-clock and concurrency coverage in packages/core/tests/limits/rate-limit.test.ts, using the in-memory counter store. Done means the listed acceptance criteria pass and the core package exports the limiter with a minor changeset.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

core enhancement hacktoberfest help wanted

The server's rate limiter keeps its counts in a Map in the process (packages/server/src/rate-limit.ts). On Vercel or Workers every instance has its own map, so a visitor spread over five instances gets five times the limit. It also needs a setInterval for cleanup (packages/server/src/handler.ts, line 35), and Workers don't allow timers at global scope.

@chatcops/core now has a CounterStore interface (packages/core/src/storage/types.ts): atomic counters that reset after a while, backed by Redis, Postgres and so on. This issue is the rate limit algorithm on top of it. Wiring it into the server comes in a later PR.

What to do
Create packages/core/src/limits/rate-limit.ts:

export interface RateLimitRule {
  limit: number;      // requests allowed per window
  windowMs: number;
}

export interface RateLimitResult {
  allowed: boolean;
  /** Requests left in the current window, never below 0. */
  remaining: number;
  /** When denied: how long until a request would be allowed again. */
  retryAfterMs?: number;
}

export function createRateLimiter(counters: CounterStore, rule: RateLimitRule, options?: { prefix?: string; now?: () => number }): {
  check(key: string): Promise<RateLimitResult>;
};

Use a sliding window built from two fixed windows. It's smooth at window edges (no burst of 2x the limit at the boundary) and needs only two counters:

  • The window index is Math.floor(now / windowMs). Count this request with counters.increment(${prefix}:${key}:${index}, 1, 2 * windowMs), and read the previous window's counter with get.
  • The estimated count is previous * (1 - elapsedInWindow / windowMs) + current. Allow the request when it's at most limit.
  • Denied requests still count, so a client that keeps hammering stays limited.
  • retryAfterMs is an estimate: the time until the estimate drops back under the limit, at least 1 ms and at most windowMs. Explain the formula in a comment.
  • prefix defaults to 'rl'. Validate limit > 0 and windowMs > 0 like RateLimiter does.

Where to look

  • packages/server/src/rate-limit.ts (today's limiter and its tests in packages/server/tests/rate-limit.test.ts)
  • packages/core/src/storage/memory.ts (memoryStorage().counters, use it in the tests with a fake now)
  • Cloudflare's write-up of the same sliding window idea

Acceptance criteria

  • New packages/core/src/limits/rate-limit.ts and packages/core/tests/limits/rate-limit.test.ts, exported from @chatcops/core
  • Tests with a fake clock: the first limit requests pass and the next one doesn't; the count decays across the window boundary (half the previous window still counts at the midpoint); keys don't affect each other; retryAfterMs is set when denied and within bounds
  • A test with 30 concurrent check() calls against a limit of 10 allows exactly 10
  • Changeset for @chatcops/core (minor)
  • pnpm test:coverage and pnpm lint pass

Want to work on this? Comment below and I'll assign it to you. Please take one issue at a time, branch off dev, and open your PR against dev with Closes #<this issue number>. Setup notes (pnpm, build before test) are in CONTRIBUTING.md.

Vorherrschende Sprache
TypeScript
Sterne
13
Forks
7
Ø Merge
3 Std. 33 Min.
Gemergte PRs (30 T.)
176

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus codercops/chatcops

Alle Issues in codercops/chatcops

Ähnliche Issues

Weitere Issues zu TypeScript

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.