export class ConcurrencyLimiter { private running = 0; private queue: Array<() => void> = []; private readonly maxConcurrency: number; private activeSet = new Set>(); constructor(maxConcurrency: number) { this.maxConcurrency = Math.max(1, maxConcurrency); } async acquire(): Promise { if (this.running < this.maxConcurrency) { this.running++; return; } return new Promise((resolve) => { this.queue.push(resolve); }); } release(): void { this.running--; if (this.queue.length > 0) { this.running++; const next = this.queue.shift()!; next(); } } track(promise: Promise): Promise { this.activeSet.add(promise); promise.finally(() => this.activeSet.delete(promise)); return promise; } async drain(): Promise { await Promise.allSettled(this.activeSet); } get activeCount(): number { return this.running; } get pendingCount(): number { return this.queue.length; } }