| 129 | const cache = new Map<string, { readonly allowed: boolean; readonly expiresAtMs: number }>(); |
| 130 | |
| 131 | const writeCache = (organizationId: string, allowed: boolean, nowMs: number): void => { |
| 132 | if (cache.size >= BALANCE_CACHE_MAX_ENTRIES) { |
| 133 | for (const [key, entry] of cache) { |
| 134 | if (entry.expiresAtMs <= nowMs) cache.delete(key); |
| 135 | } |
| 136 | // Still saturated after dropping expired entries: reset rather than grow. |
| 137 | if (cache.size >= BALANCE_CACHE_MAX_ENTRIES) cache.clear(); |
| 138 | } |
| 139 | cache.set(organizationId, { allowed, expiresAtMs: nowMs + BALANCE_CACHE_TTL_MS }); |
| 140 | }; |
| 141 | |
| 142 | const toDecision = (organizationId: string, allowed: boolean): GateDecision => |
| 143 | allowed |