ns-ui / diff-unified-viewer

Pull request #482 — rate limiter

Left-rail markers stand in for red/green: a solid bar for additions, a hairline hatch for deletions, both derived from the same ink. Any line can carry a widget — an agent's review note, a teammate's comment, or a suggested edit with its own controls.

src/lib/rate-limiter.ts+9 −5
Unified view
diff --git a/src/lib/rate-limiter.ts b/src/lib/rate-limiter.ts
index 4b1f9a2..7c3e881 100644
src/lib/rate-limiter.ts
@@ -1,17 +1,21 @@ export interface RateLimiterOptions {
11export interface RateLimiterOptions {
22 windowMs: number;
33 max: number;
4+ keyPrefix?: string;

Agent review

Consider documenting this with a JSDoc comment, since it changes the public options shape callers pass in.
45}
56 
67export class RateLimiter {
78 private hits = new Map<string, number[]>();
9+ private readonly prefix: string;
810 
911 constructor(private options: RateLimiterOptions) {
12+ this.prefix = options.keyPrefix ?? "rl";
1013 }
1114 
12− check(key: string): boolean {

Comment · @priya

Renaming the param to rawKey here reads well, but check callers of check() outside this file too.
13− const now = Date.now();
14− const bucket = this.hits.get(key) ?? [];
15+ check(rawKey: string): boolean {
16+ const key = `${this.prefix}:${rawKey}`;

Suggested edit

Guard against an empty rawKey so the derived key can never collide with the bare prefix.

17+ const now = Date.now();
18+ const bucket = this.hits.get(key) ?? [];
1519 const cutoff = now - this.options.windowMs;
1620 const recent = bucket.filter((t) => t > cutoff);
1721 
@@ -18,7 +22,7 @@ export class RateLimiter {
1822 return true;
1923 }
2024 
21− reset(key: string): void {
22− this.hits.delete(key);
25+ reset(rawKey: string): void {
26+ this.hits.delete(`${this.prefix}:${rawKey}`);
2327 }
2428}