Problem
cursorIdentityCache in worker/cursor.ts is a plain Map<string, { identity, expiresAt }>. Entries are inserted with a 1-hour TTL (expiresAt = now + 60 * 60 * 1000) but expired entries are never removed. The cache only checks expiration on read (getCursorAccountIdentity), so keys that are never looked up again accumulate indefinitely.
In a Cloudflare Worker this is partially mitigated by isolate lifecycle, but if the isolate persists (high-traffic worker) the Map grows unbounded for any rotating or one-off API keys.
Location
worker/cursor.ts — cursorIdentityCache (line 14)
Proposed Fix
Evict expired entries periodically: when set() is called, scan and remove all entries whose expiresAt has passed. This is O(n) in cache size but n is expected to be very small (one entry per active API key).
Alternatively, evict on get() when an expired entry is found (lazy eviction), plus the periodic scan on set() as a hedge.
Impact
- No API change
- No behavioral change for valid cached entries
- Fixes potential memory leak in long-lived isolates
Problem
cursorIdentityCacheinworker/cursor.tsis a plainMap<string, { identity, expiresAt }>. Entries are inserted with a 1-hour TTL (expiresAt = now + 60 * 60 * 1000) but expired entries are never removed. The cache only checks expiration on read (getCursorAccountIdentity), so keys that are never looked up again accumulate indefinitely.In a Cloudflare Worker this is partially mitigated by isolate lifecycle, but if the isolate persists (high-traffic worker) the Map grows unbounded for any rotating or one-off API keys.
Location
worker/cursor.ts—cursorIdentityCache(line 14)Proposed Fix
Evict expired entries periodically: when
set()is called, scan and remove all entries whoseexpiresAthas passed. This is O(n) in cache size but n is expected to be very small (one entry per active API key).Alternatively, evict on
get()when an expired entry is found (lazy eviction), plus the periodic scan onset()as a hedge.Impact