🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

regulo

Package Overview
Dependencies
Maintainers
1
Versions
13
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

regulo - npm Package Compare versions

Comparing version
1.3.1
to
1.3.4
+1
-1
dist/index.cjs

@@ -1,2 +0,2 @@

'use strict';var a=class extends Error{constructor(e,t){super(e),this.name="SemaphoreError",this.code=t;}};var l=(o,e,t,i,r=true,s=true)=>{if(typeof o!="number"||Number.isNaN(o))throw new a(`${e} must be a valid number`,"INVALID_ARGUMENT");if(r&&!Number.isInteger(o))throw new a(`${e} must be an integer`,"INVALID_ARGUMENT");if(s?o<t:o<=t)throw new a(`${e} must be ${s?">=":">"} ${t}`,"INVALID_ARGUMENT");if(s?o>i:o>=i)throw new a(`${e} must be ${s?"<=":"<"} ${i}`,"INVALID_ARGUMENT");return o};var w=class{constructor(e){this._inFlight=0;this.capacity=e,this._available=e;}get available(){return this._available}get inFlight(){return this._inFlight}get isFull(){return this._available===0}hasCapacityFor(e){return this._available>=e}acquire(e=1){this._available-=e,this._inFlight+=e;}release(e=1){this._available=Math.min(this._available+e,this.capacity),this._inFlight=this._inFlight<e?0:this._inFlight-e;}assertInvariant(e){if(!e)return;let t=this._inFlight+this._available;t!==this.capacity&&console.error(`[Semaphore] Invariant violation: inFlight(${this._inFlight}) + available(${this._available}) = ${t}, expected capacity(${this.capacity})`);}reset(){this._available=this.capacity,this._inFlight=0;}};var A=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=e,this.stepMs=t,this.buckets=new Int32Array(e*2),this.timestamps=new Float64Array(e);}idx(){let e=Date.now();if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs)*this.stepMs,i=Math.floor(t/this.stepMs)%this.size;return this.timestamps[i]!==t&&(this.timestamps[i]=t,this.buckets[i*2]=0,this.buckets[i*2+1]=0),this.cachedIndex=i,this.cachedUntil=t+this.stepMs,i}addAcquired(){this.buckets[this.idx()*2]++;}addTimeout(){this.buckets[this.idx()*2+1]++;}snapshot(){let e=Date.now(),t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0;for(let s=0;s<this.size;s++)this.timestamps[s]>=t&&(i+=this.buckets[s*2],r+=this.buckets[s*2+1]);return {acquired:i,timeouts:r}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.buckets.fill(0),this.timestamps.fill(0);}},f=class{constructor(e={}){this.state="closed";this.openUntil=0;this.probeInFlight=false;this._probeTaskId=null;if(this.threshold=l(e.threshold??.5,"SaturationCircuitBreaker threshold",0,1,false,false),this.window=l(e.window??1e4,"SaturationCircuitBreaker window",1e3,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketWidth=l(e.windowBucketWidth??1e3,"SaturationCircuitBreaker windowBucketWidth",1,Number.MAX_SAFE_INTEGER,true,true),this.cooldown=l(e.cooldown??5e3,"SaturationCircuitBreaker cooldown",1e3,Number.MAX_SAFE_INTEGER,true,true),this.minThroughput=l(e.minThroughput??10,"SaturationCircuitBreaker minThroughput",1,Number.MAX_SAFE_INTEGER,true,true),this.minFailures=l(e.minFailures??5,"SaturationCircuitBreaker minFailures",1,Number.MAX_SAFE_INTEGER,true,true),this.eventWindow=new A(Math.ceil(this.window/this.windowBucketWidth),this.windowBucketWidth),this.window<this.windowBucketWidth)throw new a("SaturationCircuitBreaker window must be >= windowBucketWidth","INVALID_ARGUMENT");if(this.minThroughput<this.minFailures)throw new a("SaturationCircuitBreaker minThroughput must be >= minFailures","INVALID_ARGUMENT")}get isClosed(){return this.state==="closed"}get isOpen(){return this.state==="open"}get isHalfOpen(){return this.state==="half-open"}get hasProbeInFlight(){return this.probeInFlight}get probeTaskId(){return this._probeTaskId}get cooldownRemaining(){return this.isOpen?Math.max(0,this.openUntil-Date.now()):0}trackAttempt(){this.state==="closed"&&this.eventWindow.addAcquired();}recordFailure(){this.eventWindow.addTimeout();}checkAndTransition(){return this.state!=="open"||Date.now()<this.openUntil?false:(this.state="half-open",this.probeInFlight=false,this._probeTaskId=null,true)}evaluateAndTrip(){if(this.state!=="closed")return {tripped:false};let{timeouts:e,acquired:t}=this.eventWindow.snapshot();if(t<this.minThroughput||e<this.minFailures)return {tripped:false};let i=e/t;return i<this.threshold?{tripped:false}:(this.state="open",this.openUntil=Date.now()+this.cooldown,{tripped:true,timeoutRate:i,failures:e,attempts:t})}markProbeInFlight(){this.probeInFlight=true;}claimProbeSlot(e){this.probeInFlight=true,this._probeTaskId=e;}releaseProbeSlot(){this.probeInFlight=false,this._probeTaskId=null;}handleProbeSuccess(){this.state="closed",this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}handleProbeFailure(){this.state="open",this.probeInFlight=false,this._probeTaskId=null,this.openUntil=Date.now()+this.cooldown;}reset(){this.state="closed",this.openUntil=0,this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}};var T=class{constructor(e={}){this.delay=0;this.lastTimestamp=0;if(this.initialTimeout=l(e.initialTimeout??50,"BackoffTracker initialTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.maxTimeout=l(e.maxTimeout??2e3,"BackoffTracker maxTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.decayFactor=l(e.decayFactor??.5,"BackoffTracker decayFactor",0,1,false,false),this.maxTimeout<this.initialTimeout)throw new a("BackoffTracker maxTimeout must be >= initialTimeout","INVALID_ARGUMENT")}get currentDelay(){if(this.delay===0)return 0;let e=(Date.now()-this.lastTimestamp)/1e3;if(e<=0)return this.delay;let t=this.delay*Math.pow(this.decayFactor,e);return t<1?0:t}onTimeout(){let e=this.currentDelay,t=e>0?e*2:this.initialTimeout;this.delay=Math.min(t,this.maxTimeout),this.lastTimestamp=Date.now();}reset(){this.delay=0,this.lastTimestamp=0;}};var y=class{constructor(e){this.prev=null;this.next=null;this.heapIndex=-1;this.completed=false;this.id=e.id,this.priority=e.priority,this.enqueueTime=e.enqueueTime,this.isProbe=e.isProbe,this.weight=e.weight??1,this._resolve=e.resolve,this._reject=e.reject,this.abortSignal=e.abortSignal;}arm(e){this.abortSignal&&(this.abortListener=()=>{this.claim()&&e();},this.abortSignal.addEventListener("abort",this.abortListener));}dispatch(e){return this.claim()?(this._resolve(e()),true):false}discard(e){return this.claim()?(this._reject(e),true):false}claim(){return this.completed?false:(this.completed=true,this.abortSignal&&this.abortListener&&this.abortSignal.removeEventListener("abort",this.abortListener),true)}reject(e){this._reject(e);}};var S=class{constructor(e){this.heap=[];this.compare=e;}get size(){return this.heap.length}isEmpty(){return this.heap.length===0}peek(){return this.heap[0]}toArray(){return [...this.heap]}has(e){return e.heapIndex>=0&&this.heap[e.heapIndex]===e}clear(){for(let e of this.heap)e.heapIndex=-1;this.heap=[];}insert(e){if(e.heapIndex>=0)throw new a("Item is already in a heap","INVALID_ARGUMENT");let t=this.heap.length;this.heap.push(e),e.heapIndex=t,this._bubbleUp(t);}pop(){if(this.heap.length===0)return;let e=this.heap[0];e.heapIndex=-1;let t=this.heap.pop();return this.heap.length>0&&t!==e&&(this.heap[0]=t,t.heapIndex=0,this._bubbleDown(0)),e}delete(e){let t=e.heapIndex;if(t<0||this.heap[t]!==e)return;e.heapIndex=-1;let i=this.heap.pop();if(t===this.heap.length||i===e)return e;this.heap[t]=i,i.heapIndex=t;let r=this.heap[t-1>>1];return t>0&&this.compare(i,r)<0?this._bubbleUp(t):this._bubbleDown(t),e}_swap(e,t){let i=this.heap[e],r=this.heap[t];this.heap[e]=r,this.heap[t]=i,i.heapIndex=t,r.heapIndex=e;}_bubbleUp(e){for(;e>0;){let t=e-1>>1;if(this.compare(this.heap[e],this.heap[t])<0)this._swap(e,t),e=t;else break}}_bubbleDown(e){let t=this.heap.length;for(;;){let i=e,r=2*e+1,s=2*e+2;if(r<t&&this.compare(this.heap[r],this.heap[i])<0&&(i=r),s<t&&this.compare(this.heap[s],this.heap[i])<0&&(i=s),i===e)break;this._swap(e,i),e=i;}}};var I=class{constructor(){this.head=null;this.tail=null;this._size=0;}get size(){return this._size}isEmpty(){return this._size===0}peekHead(){return this.head===null?void 0:this.head}pushTail(e){e.prev=this.tail,e.next=null,this.tail!==null?this.tail.next=e:this.head=e,this.tail=e,this._size++;}remove(e){e.prev!==null?e.prev.next=e.next:this.head=e.next,e.next!==null?e.next.prev=e.prev:this.tail=e.prev,e.prev=e.next=null,this._size--;}clear(){this.head=this.tail=null,this._size=0;}};var E=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=l(e,"CombinedWindow size",1,Number.MAX_SAFE_INTEGER,true,true),this.stepMs=l(t,"CombinedWindow stepMs",1,Number.MAX_SAFE_INTEGER,true,true),this.timestamps=new Float64Array(e),this.acquired=new Int32Array(e),this.released=new Int32Array(e),this.timeouts=new Int32Array(e),this.ifSum=new Float64Array(e),this.ifCount=new Int32Array(e),this.ifMax=new Float64Array(e),this.qSum=new Float64Array(e),this.qCount=new Int32Array(e),this.qMax=new Float64Array(e),this.latSum=new Float64Array(e),this.latCount=new Int32Array(e);}bucket(e){if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs),i=t*this.stepMs,r=t%this.size;return this.timestamps[r]!==i&&(this.timestamps[r]=i,this.acquired[r]=0,this.released[r]=0,this.timeouts[r]=0,this.ifSum[r]=0,this.ifCount[r]=0,this.ifMax[r]=0,this.qSum[r]=0,this.qCount[r]=0,this.qMax[r]=0,this.latSum[r]=0,this.latCount[r]=0),this.cachedIndex=r,this.cachedUntil=i+this.stepMs,r}addInflight(e,t){this.ifSum[e]+=t,this.ifCount[e]++,t>this.ifMax[e]&&(this.ifMax[e]=t);}addQueue(e,t){this.qSum[e]+=t,this.qCount[e]++,t>this.qMax[e]&&(this.qMax[e]=t);}recordAcquire(e,t,i){let r=this.bucket(e);this.acquired[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordAcquireQueued(e,t,i,r){let s=this.bucket(e);this.acquired[s]++,this.latSum[s]+=t,this.latCount[s]++,this.addInflight(s,i),this.addQueue(s,r);}recordRelease(e,t,i){let r=this.bucket(e);this.released[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordTimeoutQueue(e,t){let i=this.bucket(e);this.timeouts[i]++,this.addQueue(i,t);}sampleBoth(e,t,i){let r=this.bucket(e);this.addInflight(r,t),this.addQueue(r,i);}addAcquired(e){this.acquired[this.bucket(e)]++;}addReleased(e){this.released[this.bucket(e)]++;}addTimeout(e){this.timeouts[this.bucket(e)]++;}addLatency(e,t){let i=this.bucket(e);this.latSum[i]+=t,this.latCount[i]++;}sampleInflight(e,t){this.addInflight(this.bucket(e),t);}sampleQueue(e,t){this.addQueue(this.bucket(e),t);}snapshot(e){let t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0,s=0,u=0,c=0,d=0,b=0,p=0,m=0,C=0,v=0;for(let h=0;h<this.size;h++)this.timestamps[h]<t||(i+=this.acquired[h],r+=this.released[h],s+=this.timeouts[h],u+=this.ifSum[h],c+=this.ifCount[h],this.ifMax[h]>d&&(d=this.ifMax[h]),b+=this.qSum[h],p+=this.qCount[h],this.qMax[h]>m&&(m=this.qMax[h]),C+=this.latSum[h],v+=this.latCount[h]);return {counts:{acquired:i,released:r,timeouts:s},inflight:{avg:c===0?0:u/c,max:d,samples:c},queue:{avg:p===0?0:b/p,max:m,samples:p},latency:{avg:v===0?0:C/v,count:v,total:C}}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.timestamps.fill(0),this.acquired.fill(0),this.released.fill(0),this.timeouts.fill(0),this.ifSum.fill(0),this.ifCount.fill(0),this.ifMax.fill(0),this.qSum.fill(0),this.qCount.fill(0),this.qMax.fill(0),this.latSum.fill(0),this.latCount.fill(0);}},R=[{size:60,stepMs:1e3},{size:60,stepMs:5e3},{size:60,stepMs:15e3},{size:60,stepMs:6e4},{size:60,stepMs:144e4}],k=class{constructor(e=R){this._totalAcquiredFast=0;this._totalAcquiredQueued=0;this._totalReleased=0;this._totalTimeouts=0;this._totalAborts=0;this._capacity=0;this._circuitOpen=false;this._circuitHalfOpen=false;if(e.length===0)throw new a("SemaphoreMetrics requires at least one WindowOptions","INVALID_ARGUMENT");this.windows=e.map(({size:r,stepMs:s})=>new E(r,s)),this.windowLabels=e.map(({size:r,stepMs:s})=>{let u=r*s;return u>=36e5&&u%36e5===0?`${u/36e5}h`:u>=6e4&&u%6e4===0?`${u/6e4}m`:u>=1e3&&u%1e3===0?`${u/1e3}s`:`${u}ms`});let t=new Set;for(let r of this.windowLabels){if(t.has(r))throw new a(`SemaphoreMetrics windows produce duplicate label "${r}" (two windows cover the same horizon)`,"INVALID_ARGUMENT");t.add(r);}let i=0;for(let r=1;r<e.length;r++)e[r].size*e[r].stepMs<e[i].size*e[i].stepMs&&(i=r);this.primaryLabel=this.windowLabels[i],this.primaryWindowMs=e[i].size*e[i].stepMs;}onAcquireFast(e,t,i){this._totalAcquiredFast++;for(let r of this.windows)r.recordAcquire(e,t,i);}onAcquireQueued(e,t,i,r){this._totalAcquiredQueued++;for(let s of this.windows)s.recordAcquireQueued(e,t,i,r);}onRelease(e,t,i){this._totalReleased++;for(let r of this.windows)r.recordRelease(e,t,i);}onTimeout(e,t){this._totalTimeouts++;for(let i of this.windows)i.recordTimeoutQueue(e,t);}onAbort(e,t){this._totalAborts++;for(let i of this.windows)i.sampleQueue(e,t);}sampleGauges(e,t,i){for(let r of this.windows)r.sampleBoth(e,t,i);}sampleQueueDepthAt(e,t){for(let i of this.windows)i.sampleQueue(e,t);}markAcquireFast(){this._totalAcquiredFast++;let e=Date.now();for(let t of this.windows)t.addAcquired(e);}markAcquireQueued(e){this._totalAcquiredQueued++;let t=Date.now();for(let i of this.windows)i.addAcquired(t),i.addLatency(t,e);}markReleased(){this._totalReleased++;let e=Date.now();for(let t of this.windows)t.addReleased(e);}markTimeout(){this._totalTimeouts++;let e=Date.now();for(let t of this.windows)t.addTimeout(e);}markAbort(){this._totalAborts++;}sampleInFlight(e){let t=Date.now();for(let i of this.windows)i.sampleInflight(t,e);}sampleQueueDepth(e){let t=Date.now();for(let i of this.windows)i.sampleQueue(t,e);}markCapacityChange(e){this._capacity=e;}markCircuitOpen(){this._circuitOpen=true,this._circuitHalfOpen=false;}markCircuitHalfOpen(){this._circuitOpen=false,this._circuitHalfOpen=true;}markCircuitClose(){this._circuitOpen=false,this._circuitHalfOpen=false;}getSnapshot(){let e=Date.now(),t={},i=0,r=0;for(let s=0;s<this.windowLabels.length;s++){let u=this.windows[s].snapshot(e);t[this.windowLabels[s]]=u,s===0&&(i=u.inflight.avg,r=u.queue.avg);}return {windows:t,meta:{inFlightLastMinute:Math.round(i),queueDepthLastMinute:Math.round(r),totalAcquiredFast:this._totalAcquiredFast,totalAcquiredQueued:this._totalAcquiredQueued,totalReleased:this._totalReleased,totalTimeouts:this._totalTimeouts,totalAborts:this._totalAborts,capacity:this._capacity,circuitOpen:this._circuitOpen,circuitHalfOpen:this._circuitHalfOpen}}}reset(){for(let e of this.windows)e.reset();this._totalAcquiredFast=0,this._totalAcquiredQueued=0,this._totalReleased=0,this._totalTimeouts=0,this._totalAborts=0,this._capacity=0,this._circuitOpen=false,this._circuitHalfOpen=false;}destroy(){this.reset();}};var _={fifo:(o,e)=>o.id-e.id,lifo:(o,e)=>e.id-o.id,fifoWithPriority:(o,e)=>o.priority-e.priority||o.id-e.id,lifoWithPriority:(o,e)=>o.priority-e.priority||e.id-o.id};function x(o){if(o.comparator!==void 0){if(typeof o.comparator!="function")throw new a("Semaphore comparator must be a function","INVALID_ARGUMENT");return o.comparator}let e=o.queueOrder??"fifoWithPriority",t=_[e];if(t===void 0)throw new a(`Semaphore queueOrder must be one of: ${Object.keys(_).join(", ")} (got ${JSON.stringify(e)})`,"INVALID_ARGUMENT");return t}function F(o){let e=x(o);return (t,i)=>{if(t.isProbe!==i.isProbe)return t.isProbe?-1:1;let r=e(t,i);return typeof r!="number"||Number.isNaN(r)?t.id-i.id:r}}var n={TASKACQUIRE:"task-acquire",TASKRELEASE:"task-release",TASKTIMEOUT:"task-timeout",TASKABORT:"task-abort",QUEUEPURGE:"queue-purge",QUEUEEVICT:"queue-evict",CIRCUITOPEN:"circuit-open",CIRCUITHALFOPEN:"circuit-half-open",CIRCUITCLOSE:"circuit-close",SHUTDOWN:"shutdown"};var M=class{constructor(e,t={}){this.pendingReleaseCount=0;this.releaseGeneration=0;this.scheduled=false;this.isShutdown=false;this.taskIdCounter=0;this.totalAcquired=0;this.totalReleased=0;this.totalTimeouts=0;this.totalEvictions=0;this.eventListeners=new Map;this.drainPromise=null;this.drainResolve=null;this.purgeIntervalId=null;this.timeoutTimerId=null;this._runSchedulerBound=()=>{this._runScheduler();};if(l(e,"Semaphore count",0,Number.MAX_SAFE_INTEGER,true,false),this.purgeIntervalMs=l(t.purgeIntervalMs??3e3,"Semaphore purgeIntervalMs",500,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxTimeout=l(t.queueMaxTimeout??1e4,"Semaphore queueMaxTimeout",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxLength=l(t.queueMaxLength??1024,"Semaphore queueMaxLength",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxAge=l(t.queueMaxAge??3e4,"Semaphore queueMaxAge",1,Number.MAX_SAFE_INTEGER,true,true),this.rejectOnFull=t.rejectOnFull??false,this.metricsEnabled=t.metricsEnabled??true,this.debug=t.debug??false,t.circuitBreakerFailurePredicate!==void 0&&typeof t.circuitBreakerFailurePredicate!="function")throw new a("Semaphore circuitBreakerFailurePredicate must be a function","INVALID_ARGUMENT");this.failurePredicate=t.circuitBreakerFailurePredicate;let i=F({queueOrder:t.queueOrder,comparator:t.comparator});this.queue=new S(i),this.enqueueOrder=new I,this.permits=new w(e),this.circuit=t.circuitBreaker??new f({threshold:t.circuitBreakerThreshold,window:t.circuitBreakerWindow,windowBucketWidth:t.circuitBreakerWindowBucketWidth,cooldown:t.circuitBreakerCooldown,minThroughput:t.circuitBreakerMinThroughput,minFailures:t.circuitBreakerMinFailures}),this.backoff=new T({initialTimeout:t.backoffInitialTimeout,maxTimeout:t.backoffMaxTimeout,decayFactor:t.backoffDecayFactor}),this.metricsCollector=this.metricsEnabled?new k(t.metricsWindows):void 0,this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this._startPurgeInterval();}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){this.eventListeners.get(e)?.delete(t),this.eventListeners.get(e)?.size===0&&this.eventListeners.delete(e);}removeAllListeners(e){e?this.eventListeners.delete(e):this.eventListeners.clear();}hasListeners(e){let t=this.eventListeners.get(e);return t!==void 0&&t.size>0}emit(e,...t){let i=this.eventListeners.get(e);if(!(!i||i.size===0)){if(i.size===1){let r=i.values().next().value;try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}return}for(let r of Array.from(i))try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}}}_tryAcquireFast(e){return this.circuit.isHalfOpen?this.circuit.hasProbeInFlight||!this.permits.hasCapacityFor(e)?null:(this.circuit.markProbeInFlight(),this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,probe:true}),this._createRelease(true,e)):this.queue.size>0||!this.permits.hasCapacityFor(e)?null:(this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._createRelease(false,e))}_createRelease(e=false,t=1){this.pendingReleaseCount++;let i=this.releaseGeneration,r=false;return ()=>{if(r||i!==this.releaseGeneration){this.debug&&console.warn("[Semaphore] release() called after already released (no-op)");return}r=true,this.pendingReleaseCount--,this.permits.release(t),this.totalReleased++,this.metricsCollector?.onRelease(Date.now(),this.permits.inFlight,this.queue.size),e&&this.circuit.isHalfOpen&&(this.circuit.handleProbeSuccess(),this.emit(n.CIRCUITCLOSE),this.metricsCollector?.markCircuitClose(),this.debug&&console.info("[Semaphore] Circuit closed after successful probe")),this.permits.assertInvariant(this.debug),this.hasListeners(n.TASKRELEASE)&&this.emit(n.TASKRELEASE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._checkDrain(),this.schedule();}}_checkDrain(){this.drainResolve&&this.queue.size===0&&this.permits.available===this.permits.capacity&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null);}_enqueue(e){this.queue.insert(e),this.enqueueOrder.pushTail(e),this._armTimeout();}_dequeue(e){this.queue.delete(e)!==void 0&&(this.enqueueOrder.remove(e),this.enqueueOrder.size===0&&this._clearTimeout());}_armTimeout(){if(this.timeoutTimerId!==null)return;let e=this.enqueueOrder.peekHead();if(e===void 0)return;let t=Math.max(0,e.enqueueTime+this.queueMaxTimeout-Date.now());this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),t);}_clearTimeout(){this.timeoutTimerId!==null&&(clearTimeout(this.timeoutTimerId),this.timeoutTimerId=null);}_fireTimeout(){if(this.timeoutTimerId=null,this.isShutdown)return;let e=Date.now(),t=0,i=this.enqueueOrder.peekHead();for(;i!==void 0&&i.enqueueTime+this.queueMaxTimeout<=e;){let r=i.claim();this._dequeue(i),r&&(this._timeoutTask(i),t++),i=this.enqueueOrder.peekHead();}if(i!==void 0){let r=Math.max(0,i.enqueueTime+this.queueMaxTimeout-e);this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),r);}t>0&&(this._checkDrain(),this.schedule());}_evictQueueOnCircuitOpen(e){if(this.queue.size===0)return;let t=0;for(let i of this.queue.toArray()){if(i===e||i.isProbe)continue;let r=i.discard(new a("Circuit breaker opened while task was queued","CIRCUIT_OPEN"));this._dequeue(i),r&&(t++,this.totalEvictions++,this.emit(n.QUEUEEVICT,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Evicted queued task #${i.id}: circuit opened`));}t>0&&this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size);}_timeoutTask(e){if(this.totalTimeouts++,this.circuit.recordFailure(),this.backoff.onTimeout(),e.isProbe)this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe timed out");else {let t=this.circuit.evaluateAndTrip();t.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:t.timeoutRate,recentTimeouts:t.failures,total:t.attempts}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened. Rate: ${(t.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen(e));}this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.TASKTIMEOUT,{queueLength:this.queue.size,backoffDelay:this.backoff.currentDelay,taskId:e.id}),this.debug&&console.warn(`[Semaphore] Task #${e.id} timed out after ${this.queueMaxTimeout}ms`),e.reject(new a(`Semaphore acquire timed out after ${this.queueMaxTimeout}ms (queue: ${this.queue.size})`,"TIMEOUT"));}_onTaskAbort(e,t){this._dequeue(e),e.isProbe&&this.circuit.releaseProbeSlot(),this.metricsCollector?.onAbort(Date.now(),this.queue.size),this.emit(n.TASKABORT),this.debug&&console.info(`[Semaphore] Task #${e.id} aborted`),t(new a("Semaphore acquire aborted","ABORTED")),this._checkDrain(),this.schedule();}schedule(){if(this.scheduled||this.isShutdown)return;this.scheduled=true;let e=this.backoff.currentDelay;e>0?setTimeout(this._runSchedulerBound,e).unref?.():queueMicrotask(this._runSchedulerBound);}_runScheduler(){if(!this.isShutdown){this.scheduled=false;try{for(;this.queue.size>0&&!this.circuit.isOpen;){let e=this.queue.peek();if(!e||this.circuit.isHalfOpen&&e.id!==this.circuit.probeTaskId||!this.permits.hasCapacityFor(e.weight))break;let t=this.queue.pop();this.enqueueOrder.remove(t),this.enqueueOrder.size===0&&this._clearTimeout();let i=Date.now(),r=Math.max(0,i-t.enqueueTime);this.permits.acquire(t.weight),this.totalAcquired++,this.metricsCollector?.onAcquireQueued(i,r,this.permits.inFlight,this.queue.size),this.permits.assertInvariant(this.debug),t.dispatch(()=>this._createRelease(t.isProbe,t.weight))&&this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,...t.isProbe?{probe:!0}:{}});}this._checkDrain();}catch(e){e instanceof Error?console.error("[Semaphore] Scheduler error:",e.message,e.stack):console.error("[Semaphore] Scheduler error:",e);}}}_startPurgeInterval(){this.purgeIntervalId!==null&&clearInterval(this.purgeIntervalId),this.purgeIntervalId=setInterval(()=>{this.isShutdown||this._purgeStaleTasks();},this.purgeIntervalMs),this.purgeIntervalId.unref?.();}_purgeStaleTasks(){let e=Date.now(),t=this.queue.size,i=this.enqueueOrder.peekHead();for(;i!==void 0&&e-i.enqueueTime>this.queueMaxAge;){this.circuit.probeTaskId===i.id&&this.circuit.releaseProbeSlot();let r=i.discard(new a(`Task purged after ${this.queueMaxAge}ms`,"PURGED"));this._dequeue(i),r&&(this.totalTimeouts++,this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.QUEUEPURGE,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Purged stale task #${i.id}`)),i=this.enqueueOrder.peekHead();}this.debug&&this.queue.size<t&&console.info(`[Semaphore] Purged ${t-this.queue.size} stale tasks`),this.queue.size<t&&(this._checkDrain(),this.schedule());}tryAcquire(e=1){return this.isShutdown||!Number.isInteger(e)||e<1||e>this.permits.capacity||(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)?null:this._tryAcquireFast(e)}acquire(e,t=0,i=1){if(this.isShutdown)return Promise.reject(new a("Semaphore is shut down","SHUTDOWN"));if(!Number.isInteger(i)||i<1||i>this.permits.capacity)return Promise.reject(new a(`Invalid weight: ${i} (must be integer in 1..${this.permits.capacity})`,"INVALID_WEIGHT"));if(typeof t!="number"||!Number.isFinite(t))return Promise.reject(new a(`Invalid priority: ${t} (must be a finite number)`,"INVALID_PRIORITY"));if(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)return Promise.reject(new a(`Circuit breaker open, retry in ${this.circuit.cooldownRemaining}ms`,"CIRCUIT_OPEN"));if(this.circuit.isHalfOpen&&this.circuit.hasProbeInFlight)return Promise.reject(new a("Circuit breaker half-open, probe in flight","CIRCUIT_HALF_OPEN"));if(e?.aborted)return Promise.reject(new a("Semaphore acquire aborted before start","ABORTED"));this.circuit.trackAttempt();let r=this._tryAcquireFast(i);if(r)return Promise.resolve(r);let s=this.circuit.isHalfOpen&&!this.circuit.hasProbeInFlight;return !s&&this.rejectOnFull?Promise.reject(new a("Semaphore at capacity (rejectOnFull)","QUEUE_FULL")):!s&&this.queue.size>=this.queueMaxLength?Promise.reject(new a(`Queue full (${this.queueMaxLength})`,"QUEUE_FULL")):new Promise((u,c)=>{let d=++this.taskIdCounter,b=Date.now(),p=s,m=new y({id:d,priority:p?Number.MIN_SAFE_INTEGER:t,enqueueTime:b,isProbe:p,resolve:u,reject:c,abortSignal:e,weight:i});m.arm(()=>this._onTaskAbort(m,c)),p&&this.circuit.claimProbeSlot(d),this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size+1),this._enqueue(m),this.schedule();})}peekQueue(){let e=[],t=this.enqueueOrder.peekHead();for(;t!==void 0;)e.push({id:t.id,priority:t.priority,enqueueTime:t.enqueueTime,weight:t.weight,isProbe:t.isProbe}),t=t.next??void 0;return e}async use(e,t,i=0,r=1){let s=await this.acquire(t,i,r),u=this.failurePredicate!==void 0&&this.circuit.isHalfOpen;try{let c=await e();return s(),c}catch(c){if(this.failurePredicate!==void 0){let d=false;try{d=this.failurePredicate(c)===!0;}catch(b){console.warn("[Semaphore] circuitBreakerFailurePredicate threw (rejection treated as non-matching):",b);}d&&(u&&this.circuit.isHalfOpen?(this.circuit.recordFailure(),this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe operation failed")):this.reportFailure());}throw s(),c}}drain(e){return this.isShutdown?Promise.reject(new a("Cannot drain: semaphore is shut down","SHUTDOWN")):(e!==void 0&&l(e,"drain timeoutMs",1,Number.MAX_SAFE_INTEGER,true,true),this.drainPromise?this.drainPromise:this.queue.size===0&&this.permits.available===this.permits.capacity?Promise.resolve():(this.drainPromise=new Promise((t,i)=>{if(this.drainResolve=t,e!==void 0){let r=setTimeout(()=>{this.drainResolve=null,this.drainPromise=null,i(new a(`drain() timed out after ${e}ms`,"TIMEOUT"));},e),s=this.drainResolve;this.drainResolve=()=>{clearTimeout(r),s();};}}),this.drainPromise))}reset(e={}){if(this.isShutdown)throw new a("Cannot reset a semaphore that has been shut down","SHUTDOWN");for(let t of this.queue.toArray())t.discard(new a("Semaphore reset","SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this._clearTimeout(),this.metricsCollector?.reset(),this.permits.reset(),this.backoff.reset(),this.circuit.reset(),this.releaseGeneration++,this.pendingReleaseCount=0,this.scheduled=false,this.isShutdown=false,this.taskIdCounter=0,this.totalAcquired=0,this.totalReleased=0,this.totalTimeouts=0,this.totalEvictions=0,e.clearListeners&&this.eventListeners.clear(),this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this._startPurgeInterval(),this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this.debug&&console.info("[Semaphore] Reset to initial state");}shutdown(e="Semaphore shutdown"){if(!this.isShutdown){this.isShutdown=true,this.debug&&console.info(`[Semaphore] Shutdown: ${e}`),this.purgeIntervalId!==null&&(clearInterval(this.purgeIntervalId),this.purgeIntervalId=null),this._clearTimeout();for(let t of this.queue.toArray())t.discard(new a(e,"SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this.metricsCollector?.destroy(),this.metricsCollector=void 0,this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this.emit(n.SHUTDOWN,e);}}cancel(){if(this.isShutdown)return;let e=this.queue.toArray();for(let t of e)t.isProbe&&this.circuit.releaseProbeSlot(),t.discard(new a("Semaphore acquire cancelled","CANCELLED")),this._dequeue(t);this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size),this.debug&&console.info(`[Semaphore] Cancelled ${e.length} queued tasks`),this._checkDrain(),this.schedule();}reportFailure(){if(this.isShutdown)return;this.circuit.recordFailure();let e=this.circuit.evaluateAndTrip();e.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:e.timeoutRate,recentTimeouts:e.failures,total:e.attempts,reason:"reported-failure"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened via reportFailure(). Rate: ${(e.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen());}status(){let e=this.metricsCollector?.getSnapshot()??null,t=this.metricsCollector!==void 0?e?.windows?.[this.metricsCollector.primaryLabel]?.counts:void 0,i=(this.metricsCollector?.primaryWindowMs??6e4)/1e3,r=t?.acquired??0,s=t?.timeouts??0,u=this.enqueueOrder.peekHead(),c=u===void 0?0:Math.max(0,Date.now()-u.enqueueTime);return {status:{running:this.permits.capacity-this.permits.available,queued:this.queue.size,available:this.permits.available,inFlight:this.permits.inFlight,pendingReleases:this.pendingReleaseCount,circuitOpen:this.circuit.isOpen,circuitHalfOpen:this.circuit.isHalfOpen,backoffDelay:Math.round(this.backoff.currentDelay),requestsPerSecond:+(r/i).toFixed(2),timeoutRate1m:r+s>0?+(s/(r+s)*100).toFixed(1):0,queueAge:c},lifetime:{totalAcquired:this.totalAcquired,totalReleased:this.totalReleased,totalTimeouts:this.totalTimeouts,totalEvictions:this.totalEvictions,circuitBreakerCooldownRemaining:this.circuit.cooldownRemaining},metrics:e}}get availablePermits(){return this.permits.available}isAvailable(){return !this.isShutdown&&!this.circuit.isOpen&&!this.permits.isFull}get capacity(){return this.permits.capacity}get circuitState(){return this.circuit.state}get queueLength(){return this.queue.size}};var O={tripped:false},q=class{constructor(){this.state="closed";this.isOpen=false;this.isHalfOpen=false;this.hasProbeInFlight=false;this.probeTaskId=null;this.cooldownRemaining=0;}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return O}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){}};var P={tripped:false},g=class{constructor(){this.state="closed";this.hasProbeInFlight=false;this.probeTaskId=null;}get isOpen(){return this.state==="open"}get isHalfOpen(){return false}get cooldownRemaining(){return 0}open(){this.state="open";}close(){this.state="closed";}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return P}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){this.state="closed";}};exports.ManualCircuitBreaker=g;exports.NoopCircuitBreaker=q;exports.QUEUE_ORDERINGS=_;exports.SaturationCircuitBreaker=f;exports.Semaphore=M;exports.SemaphoreError=a;exports.SemaphoreEvents=n;//# sourceMappingURL=index.cjs.map
'use strict';var a=class extends Error{constructor(e,t){super(e),this.name="SemaphoreError",this.code=t;}};var l=(o,e,t,i,r=true,s=true)=>{if(typeof o!="number"||Number.isNaN(o))throw new a(`${e} must be a valid number`,"INVALID_ARGUMENT");if(r&&!Number.isInteger(o))throw new a(`${e} must be an integer`,"INVALID_ARGUMENT");if(s?o<t:o<=t)throw new a(`${e} must be ${s?">=":">"} ${t}`,"INVALID_ARGUMENT");if(s?o>i:o>=i)throw new a(`${e} must be ${s?"<=":"<"} ${i}`,"INVALID_ARGUMENT");return o};var w=class{constructor(e){this._inFlight=0;this.capacity=e,this._available=e;}get available(){return this._available}get inFlight(){return this._inFlight}get isFull(){return this._available===0}hasCapacityFor(e){return this._available>=e}acquire(e=1){this._available-=e,this._inFlight+=e;}release(e=1){this._available=Math.min(this._available+e,this.capacity),this._inFlight=this._inFlight<e?0:this._inFlight-e;}assertInvariant(e){if(!e)return;let t=this._inFlight+this._available;t!==this.capacity&&console.error(`[Semaphore] Invariant violation: inFlight(${this._inFlight}) + available(${this._available}) = ${t}, expected capacity(${this.capacity})`);}reset(){this._available=this.capacity,this._inFlight=0;}};var A=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=e,this.stepMs=t,this.buckets=new Int32Array(e*2),this.timestamps=new Float64Array(e);}idx(){let e=Date.now();if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs)*this.stepMs,i=Math.floor(t/this.stepMs)%this.size;return this.timestamps[i]!==t&&(this.timestamps[i]=t,this.buckets[i*2]=0,this.buckets[i*2+1]=0),this.cachedIndex=i,this.cachedUntil=t+this.stepMs,i}addAcquired(){this.buckets[this.idx()*2]++;}addTimeout(){this.buckets[this.idx()*2+1]++;}snapshot(){let e=Date.now(),t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0;for(let s=0;s<this.size;s++)this.timestamps[s]>=t&&(i+=this.buckets[s*2],r+=this.buckets[s*2+1]);return {acquired:i,timeouts:r}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.buckets.fill(0),this.timestamps.fill(0);}},f=class{constructor(e={}){this.state="closed";this.openUntil=0;this.probeInFlight=false;this._probeTaskId=null;if(this.threshold=l(e.threshold??.5,"SaturationCircuitBreaker threshold",0,1,false,false),this.window=l(e.window??1e4,"SaturationCircuitBreaker window",1e3,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketWidth=l(e.windowBucketWidth??1e3,"SaturationCircuitBreaker windowBucketWidth",1,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketCount=Math.ceil(this.window/this.windowBucketWidth),this.cooldown=l(e.cooldown??5e3,"SaturationCircuitBreaker cooldown",1e3,Number.MAX_SAFE_INTEGER,true,true),this.minThroughput=l(e.minThroughput??10,"SaturationCircuitBreaker minThroughput",1,Number.MAX_SAFE_INTEGER,true,true),this.minFailures=l(e.minFailures??5,"SaturationCircuitBreaker minFailures",1,Number.MAX_SAFE_INTEGER,true,true),this.window<this.windowBucketWidth)throw new a("SaturationCircuitBreaker window must be >= windowBucketWidth","INVALID_ARGUMENT");if(this.minThroughput<this.minFailures)throw new a("SaturationCircuitBreaker minThroughput must be >= minFailures","INVALID_ARGUMENT");if(this.windowBucketCount<2)throw new a("SaturationCircuitBreaker window must span at least 2 windowBucketWidth buckets","INVALID_ARGUMENT");this.eventWindow=new A(this.windowBucketCount,this.windowBucketWidth);}get isClosed(){return this.state==="closed"}get isOpen(){return this.state==="open"}get isHalfOpen(){return this.state==="half-open"}get hasProbeInFlight(){return this.probeInFlight}get probeTaskId(){return this._probeTaskId}get cooldownRemaining(){return this.isOpen?Math.max(0,this.openUntil-Date.now()):0}trackAttempt(){this.state==="closed"&&this.eventWindow.addAcquired();}recordFailure(){this.eventWindow.addTimeout();}checkAndTransition(){return this.state!=="open"||Date.now()<this.openUntil?false:(this.state="half-open",this.probeInFlight=false,this._probeTaskId=null,true)}evaluateAndTrip(){if(this.state!=="closed")return {tripped:false};let{timeouts:e,acquired:t}=this.eventWindow.snapshot();if(t<this.minThroughput||e<this.minFailures)return {tripped:false};let i=e/t;return i<this.threshold?{tripped:false}:(this.state="open",this.openUntil=Date.now()+this.cooldown,{tripped:true,timeoutRate:i,failures:e,attempts:t})}markProbeInFlight(){this.probeInFlight=true;}claimProbeSlot(e){this.probeInFlight=true,this._probeTaskId=e;}releaseProbeSlot(){this.probeInFlight=false,this._probeTaskId=null;}handleProbeSuccess(){this.state="closed",this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}handleProbeFailure(){this.state="open",this.probeInFlight=false,this._probeTaskId=null,this.openUntil=Date.now()+this.cooldown;}reset(){this.state="closed",this.openUntil=0,this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}};var T=class{constructor(e={}){this.delay=0;this.lastTimestamp=0;if(this.initialTimeout=l(e.initialTimeout??50,"BackoffTracker initialTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.maxTimeout=l(e.maxTimeout??2e3,"BackoffTracker maxTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.decayFactor=l(e.decayFactor??.5,"BackoffTracker decayFactor",0,1,false,false),this.maxTimeout<this.initialTimeout)throw new a("BackoffTracker maxTimeout must be >= initialTimeout","INVALID_ARGUMENT")}get currentDelay(){if(this.delay===0)return 0;let e=(Date.now()-this.lastTimestamp)/1e3;if(e<=0)return this.delay;let t=this.delay*Math.pow(this.decayFactor,e);return t<1?0:t}onTimeout(){let e=this.currentDelay,t=e>0?e*2:this.initialTimeout;this.delay=Math.min(t,this.maxTimeout),this.lastTimestamp=Date.now();}reset(){this.delay=0,this.lastTimestamp=0;}};var y=class{constructor(e){this.prev=null;this.next=null;this.heapIndex=-1;this.completed=false;this.id=e.id,this.priority=e.priority,this.enqueueTime=e.enqueueTime,this.isProbe=e.isProbe,this.weight=e.weight??1,this._resolve=e.resolve,this._reject=e.reject,this.abortSignal=e.abortSignal;}arm(e){this.abortSignal&&(this.abortListener=()=>{this.claim()&&e();},this.abortSignal.addEventListener("abort",this.abortListener));}dispatch(e){return this.claim()?(this._resolve(e()),true):false}discard(e){return this.claim()?(this._reject(e),true):false}claim(){return this.completed?false:(this.completed=true,this.abortSignal&&this.abortListener&&this.abortSignal.removeEventListener("abort",this.abortListener),true)}reject(e){this._reject(e);}};var S=class{constructor(e){this.heap=[];this.compare=e;}get size(){return this.heap.length}isEmpty(){return this.heap.length===0}peek(){return this.heap[0]}toArray(){return [...this.heap]}has(e){return e.heapIndex>=0&&this.heap[e.heapIndex]===e}clear(){for(let e of this.heap)e.heapIndex=-1;this.heap=[];}insert(e){if(e.heapIndex>=0)throw new a("Item is already in a heap","INVALID_ARGUMENT");let t=this.heap.length;this.heap.push(e),e.heapIndex=t,this._bubbleUp(t);}pop(){if(this.heap.length===0)return;let e=this.heap[0];e.heapIndex=-1;let t=this.heap.pop();return this.heap.length>0&&t!==e&&(this.heap[0]=t,t.heapIndex=0,this._bubbleDown(0)),e}delete(e){let t=e.heapIndex;if(t<0||this.heap[t]!==e)return;e.heapIndex=-1;let i=this.heap.pop();if(t===this.heap.length||i===e)return e;this.heap[t]=i,i.heapIndex=t;let r=this.heap[t-1>>1];return t>0&&this.compare(i,r)<0?this._bubbleUp(t):this._bubbleDown(t),e}_swap(e,t){let i=this.heap[e],r=this.heap[t];this.heap[e]=r,this.heap[t]=i,i.heapIndex=t,r.heapIndex=e;}_bubbleUp(e){for(;e>0;){let t=e-1>>1;if(this.compare(this.heap[e],this.heap[t])<0)this._swap(e,t),e=t;else break}}_bubbleDown(e){let t=this.heap.length;for(;;){let i=e,r=2*e+1,s=2*e+2;if(r<t&&this.compare(this.heap[r],this.heap[i])<0&&(i=r),s<t&&this.compare(this.heap[s],this.heap[i])<0&&(i=s),i===e)break;this._swap(e,i),e=i;}}};var k=class{constructor(){this.head=null;this.tail=null;this._size=0;}get size(){return this._size}isEmpty(){return this._size===0}peekHead(){return this.head===null?void 0:this.head}pushTail(e){e.prev=this.tail,e.next=null,this.tail!==null?this.tail.next=e:this.head=e,this.tail=e,this._size++;}remove(e){e.prev!==null?e.prev.next=e.next:this.head=e.next,e.next!==null?e.next.prev=e.prev:this.tail=e.prev,e.prev=e.next=null,this._size--;}clear(){this.head=this.tail=null,this._size=0;}};var E=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=l(e,"CombinedWindow size",1,Number.MAX_SAFE_INTEGER,true,true),this.stepMs=l(t,"CombinedWindow stepMs",1,Number.MAX_SAFE_INTEGER,true,true),this.timestamps=new Float64Array(e),this.acquired=new Int32Array(e),this.released=new Int32Array(e),this.timeouts=new Int32Array(e),this.ifSum=new Float64Array(e),this.ifCount=new Int32Array(e),this.ifMax=new Float64Array(e),this.qSum=new Float64Array(e),this.qCount=new Int32Array(e),this.qMax=new Float64Array(e),this.latSum=new Float64Array(e),this.latCount=new Int32Array(e);}bucket(e){if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs),i=t*this.stepMs,r=t%this.size;return this.timestamps[r]!==i&&(this.timestamps[r]=i,this.acquired[r]=0,this.released[r]=0,this.timeouts[r]=0,this.ifSum[r]=0,this.ifCount[r]=0,this.ifMax[r]=0,this.qSum[r]=0,this.qCount[r]=0,this.qMax[r]=0,this.latSum[r]=0,this.latCount[r]=0),this.cachedIndex=r,this.cachedUntil=i+this.stepMs,r}addInflight(e,t){this.ifSum[e]+=t,this.ifCount[e]++,t>this.ifMax[e]&&(this.ifMax[e]=t);}addQueue(e,t){this.qSum[e]+=t,this.qCount[e]++,t>this.qMax[e]&&(this.qMax[e]=t);}recordAcquire(e,t,i){let r=this.bucket(e);this.acquired[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordAcquireQueued(e,t,i,r){let s=this.bucket(e);this.acquired[s]++,this.latSum[s]+=t,this.latCount[s]++,this.addInflight(s,i),this.addQueue(s,r);}recordRelease(e,t,i){let r=this.bucket(e);this.released[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordTimeoutQueue(e,t){let i=this.bucket(e);this.timeouts[i]++,this.addQueue(i,t);}sampleBoth(e,t,i){let r=this.bucket(e);this.addInflight(r,t),this.addQueue(r,i);}addAcquired(e){this.acquired[this.bucket(e)]++;}addReleased(e){this.released[this.bucket(e)]++;}addTimeout(e){this.timeouts[this.bucket(e)]++;}addLatency(e,t){let i=this.bucket(e);this.latSum[i]+=t,this.latCount[i]++;}sampleInflight(e,t){this.addInflight(this.bucket(e),t);}sampleQueue(e,t){this.addQueue(this.bucket(e),t);}snapshot(e){let t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0,s=0,u=0,c=0,d=0,b=0,p=0,m=0,g=0,v=0;for(let h=0;h<this.size;h++)this.timestamps[h]<t||(i+=this.acquired[h],r+=this.released[h],s+=this.timeouts[h],u+=this.ifSum[h],c+=this.ifCount[h],this.ifMax[h]>d&&(d=this.ifMax[h]),b+=this.qSum[h],p+=this.qCount[h],this.qMax[h]>m&&(m=this.qMax[h]),g+=this.latSum[h],v+=this.latCount[h]);return {counts:{acquired:i,released:r,timeouts:s},inflight:{avg:c===0?0:u/c,max:d,samples:c},queue:{avg:p===0?0:b/p,max:m,samples:p},latency:{avg:v===0?0:g/v,count:v,total:g}}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.timestamps.fill(0),this.acquired.fill(0),this.released.fill(0),this.timeouts.fill(0),this.ifSum.fill(0),this.ifCount.fill(0),this.ifMax.fill(0),this.qSum.fill(0),this.qCount.fill(0),this.qMax.fill(0),this.latSum.fill(0),this.latCount.fill(0);}},F=[{size:60,stepMs:1e3},{size:60,stepMs:5e3},{size:60,stepMs:15e3},{size:60,stepMs:6e4},{size:60,stepMs:144e4}],I=class{constructor(e=F){this._totalAcquiredFast=0;this._totalAcquiredQueued=0;this._totalReleased=0;this._totalTimeouts=0;this._totalAborts=0;this._capacity=0;this._circuitOpen=false;this._circuitHalfOpen=false;if(e.length===0)throw new a("SemaphoreMetrics requires at least one WindowOptions","INVALID_ARGUMENT");this.windows=e.map(({size:r,stepMs:s})=>new E(r,s)),this.windowLabels=e.map(({size:r,stepMs:s})=>{let u=r*s;return u>=36e5&&u%36e5===0?`${u/36e5}h`:u>=6e4&&u%6e4===0?`${u/6e4}m`:u>=1e3&&u%1e3===0?`${u/1e3}s`:`${u}ms`});let t=new Set;for(let r of this.windowLabels){if(t.has(r))throw new a(`SemaphoreMetrics windows produce duplicate label "${r}" (two windows cover the same horizon)`,"INVALID_ARGUMENT");t.add(r);}let i=0;for(let r=1;r<e.length;r++)e[r].size*e[r].stepMs<e[i].size*e[i].stepMs&&(i=r);this.primaryLabel=this.windowLabels[i],this.primaryWindowMs=e[i].size*e[i].stepMs;}onAcquireFast(e,t,i){this._totalAcquiredFast++;for(let r of this.windows)r.recordAcquire(e,t,i);}onAcquireQueued(e,t,i,r){this._totalAcquiredQueued++;for(let s of this.windows)s.recordAcquireQueued(e,t,i,r);}onRelease(e,t,i){this._totalReleased++;for(let r of this.windows)r.recordRelease(e,t,i);}onTimeout(e,t){this._totalTimeouts++;for(let i of this.windows)i.recordTimeoutQueue(e,t);}onAbort(e,t){this._totalAborts++;for(let i of this.windows)i.sampleQueue(e,t);}sampleGauges(e,t,i){for(let r of this.windows)r.sampleBoth(e,t,i);}sampleQueueDepthAt(e,t){for(let i of this.windows)i.sampleQueue(e,t);}markAcquireFast(){this._totalAcquiredFast++;let e=Date.now();for(let t of this.windows)t.addAcquired(e);}markAcquireQueued(e){this._totalAcquiredQueued++;let t=Date.now();for(let i of this.windows)i.addAcquired(t),i.addLatency(t,e);}markReleased(){this._totalReleased++;let e=Date.now();for(let t of this.windows)t.addReleased(e);}markTimeout(){this._totalTimeouts++;let e=Date.now();for(let t of this.windows)t.addTimeout(e);}markAbort(){this._totalAborts++;}sampleInFlight(e){let t=Date.now();for(let i of this.windows)i.sampleInflight(t,e);}sampleQueueDepth(e){let t=Date.now();for(let i of this.windows)i.sampleQueue(t,e);}markCapacityChange(e){this._capacity=e;}markCircuitOpen(){this._circuitOpen=true,this._circuitHalfOpen=false;}markCircuitHalfOpen(){this._circuitOpen=false,this._circuitHalfOpen=true;}markCircuitClose(){this._circuitOpen=false,this._circuitHalfOpen=false;}getSnapshot(){let e=Date.now(),t={},i=0,r=0;for(let s=0;s<this.windowLabels.length;s++){let u=this.windows[s].snapshot(e);t[this.windowLabels[s]]=u,s===0&&(i=u.inflight.avg,r=u.queue.avg);}return {windows:t,meta:{inFlightLastMinute:Math.round(i),queueDepthLastMinute:Math.round(r),totalAcquiredFast:this._totalAcquiredFast,totalAcquiredQueued:this._totalAcquiredQueued,totalReleased:this._totalReleased,totalTimeouts:this._totalTimeouts,totalAborts:this._totalAborts,capacity:this._capacity,circuitOpen:this._circuitOpen,circuitHalfOpen:this._circuitHalfOpen}}}reset(){for(let e of this.windows)e.reset();this._totalAcquiredFast=0,this._totalAcquiredQueued=0,this._totalReleased=0,this._totalTimeouts=0,this._totalAborts=0,this._capacity=0,this._circuitOpen=false,this._circuitHalfOpen=false;}destroy(){this.reset();}};var _={fifo:(o,e)=>o.id-e.id,lifo:(o,e)=>e.id-o.id,fifoWithPriority:(o,e)=>o.priority-e.priority||o.id-e.id,lifoWithPriority:(o,e)=>o.priority-e.priority||e.id-o.id};function x(o){if(o.comparator!==void 0){if(typeof o.comparator!="function")throw new a("Semaphore comparator must be a function","INVALID_ARGUMENT");return o.comparator}let e=o.queueOrder??"fifoWithPriority",t=_[e];if(t===void 0)throw new a(`Semaphore queueOrder must be one of: ${Object.keys(_).join(", ")} (got ${JSON.stringify(e)})`,"INVALID_ARGUMENT");return t}function R(o){let e=x(o);return (t,i)=>{if(t.isProbe!==i.isProbe)return t.isProbe?-1:1;let r=e(t,i);return typeof r!="number"||Number.isNaN(r)?t.id-i.id:r}}var n={TASKACQUIRE:"task-acquire",TASKRELEASE:"task-release",TASKTIMEOUT:"task-timeout",TASKABORT:"task-abort",QUEUEPURGE:"queue-purge",QUEUEEVICT:"queue-evict",CIRCUITOPEN:"circuit-open",CIRCUITHALFOPEN:"circuit-half-open",CIRCUITCLOSE:"circuit-close",SHUTDOWN:"shutdown"};var M=class{constructor(e,t={}){this.pendingReleaseCount=0;this.releaseGeneration=0;this.scheduled=false;this.isShutdown=false;this.taskIdCounter=0;this.totalAcquired=0;this.totalReleased=0;this.totalTimeouts=0;this.totalEvictions=0;this.eventListeners=new Map;this.drainPromise=null;this.drainResolve=null;this.purgeIntervalId=null;this.timeoutTimerId=null;this._runSchedulerBound=()=>{this._runScheduler();};if(l(e,"Semaphore count",0,Number.MAX_SAFE_INTEGER,true,false),this.purgeIntervalMs=l(t.purgeIntervalMs??3e3,"Semaphore purgeIntervalMs",500,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxTimeout=l(t.queueMaxTimeout??1e4,"Semaphore queueMaxTimeout",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxLength=l(t.queueMaxLength??1024,"Semaphore queueMaxLength",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxAge=l(t.queueMaxAge??3e4,"Semaphore queueMaxAge",1,Number.MAX_SAFE_INTEGER,true,true),this.rejectOnFull=t.rejectOnFull??false,this.metricsEnabled=t.metricsEnabled??true,this.debug=t.debug??false,t.circuitBreakerFailurePredicate!==void 0&&typeof t.circuitBreakerFailurePredicate!="function")throw new a("Semaphore circuitBreakerFailurePredicate must be a function","INVALID_ARGUMENT");this.failurePredicate=t.circuitBreakerFailurePredicate;let i=R({queueOrder:t.queueOrder,comparator:t.comparator});this.queue=new S(i),this.enqueueOrder=new k,this.permits=new w(e),this.circuit=t.circuitBreaker??new f({threshold:t.circuitBreakerThreshold,window:t.circuitBreakerWindow,windowBucketWidth:t.circuitBreakerWindowBucketWidth,cooldown:t.circuitBreakerCooldown,minThroughput:t.circuitBreakerMinThroughput,minFailures:t.circuitBreakerMinFailures}),this.backoff=new T({initialTimeout:t.backoffInitialTimeout,maxTimeout:t.backoffMaxTimeout,decayFactor:t.backoffDecayFactor}),this.metricsCollector=this.metricsEnabled?new I(t.metricsWindows):void 0,this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this._startPurgeInterval();}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){this.eventListeners.get(e)?.delete(t),this.eventListeners.get(e)?.size===0&&this.eventListeners.delete(e);}removeAllListeners(e){e?this.eventListeners.delete(e):this.eventListeners.clear();}hasListeners(e){let t=this.eventListeners.get(e);return t!==void 0&&t.size>0}emit(e,...t){let i=this.eventListeners.get(e);if(!(!i||i.size===0)){if(i.size===1){let r=i.values().next().value;try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}return}for(let r of Array.from(i))try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}}}_tryAcquireFast(e){return this.circuit.isHalfOpen?this.circuit.hasProbeInFlight||!this.permits.hasCapacityFor(e)?null:(this.circuit.markProbeInFlight(),this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,probe:true}),this._createRelease(true,e)):this.queue.size>0||!this.permits.hasCapacityFor(e)?null:(this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._createRelease(false,e))}_createRelease(e=false,t=1){this.pendingReleaseCount++;let i=this.releaseGeneration,r=false;return ()=>{if(r||i!==this.releaseGeneration){this.debug&&console.warn("[Semaphore] release() called after already released (no-op)");return}r=true,this.pendingReleaseCount--,this.permits.release(t),this.totalReleased++,this.metricsCollector?.onRelease(Date.now(),this.permits.inFlight,this.queue.size),e&&this.circuit.isHalfOpen&&(this.circuit.handleProbeSuccess(),this.emit(n.CIRCUITCLOSE),this.metricsCollector?.markCircuitClose(),this.debug&&console.info("[Semaphore] Circuit closed after successful probe")),this.permits.assertInvariant(this.debug),this.hasListeners(n.TASKRELEASE)&&this.emit(n.TASKRELEASE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._checkDrain(),this.schedule();}}_checkDrain(){this.drainResolve&&this.queue.size===0&&this.permits.available===this.permits.capacity&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null);}_enqueue(e){this.queue.insert(e),this.enqueueOrder.pushTail(e),this._armTimeout();}_dequeue(e){this.queue.delete(e)!==void 0&&(this.enqueueOrder.remove(e),this.enqueueOrder.size===0&&this._clearTimeout());}_armTimeout(){if(this.timeoutTimerId!==null)return;let e=this.enqueueOrder.peekHead();if(e===void 0)return;let t=Math.max(0,e.enqueueTime+this.queueMaxTimeout-Date.now());this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),t);}_clearTimeout(){this.timeoutTimerId!==null&&(clearTimeout(this.timeoutTimerId),this.timeoutTimerId=null);}_fireTimeout(){if(this.timeoutTimerId=null,this.isShutdown)return;let e=Date.now(),t=0,i=this.enqueueOrder.peekHead();for(;i!==void 0&&i.enqueueTime+this.queueMaxTimeout<=e;){let r=i.claim();this._dequeue(i),r&&(this._timeoutTask(i),t++),i=this.enqueueOrder.peekHead();}if(i!==void 0){let r=Math.max(0,i.enqueueTime+this.queueMaxTimeout-e);this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),r);}t>0&&(this._checkDrain(),this.schedule());}_evictQueueOnCircuitOpen(e){if(this.queue.size===0)return;let t=0;for(let i of this.queue.toArray()){if(i===e||i.isProbe)continue;let r=i.discard(new a("Circuit breaker opened while task was queued","CIRCUIT_OPEN"));this._dequeue(i),r&&(t++,this.totalEvictions++,this.emit(n.QUEUEEVICT,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Evicted queued task #${i.id}: circuit opened`));}t>0&&this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size);}_timeoutTask(e){if(this.totalTimeouts++,this.circuit.recordFailure(),this.backoff.onTimeout(),e.isProbe)this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe timed out");else {let t=this.circuit.evaluateAndTrip();t.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:t.timeoutRate,recentTimeouts:t.failures,total:t.attempts}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened. Rate: ${(t.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen(e));}this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.TASKTIMEOUT,{queueLength:this.queue.size,backoffDelay:this.backoff.currentDelay,taskId:e.id}),this.debug&&console.warn(`[Semaphore] Task #${e.id} timed out after ${this.queueMaxTimeout}ms`),e.reject(new a(`Semaphore acquire timed out after ${this.queueMaxTimeout}ms (queue: ${this.queue.size})`,"TIMEOUT"));}_onTaskAbort(e,t){this._dequeue(e),e.isProbe&&this.circuit.releaseProbeSlot(),this.metricsCollector?.onAbort(Date.now(),this.queue.size),this.emit(n.TASKABORT),this.debug&&console.info(`[Semaphore] Task #${e.id} aborted`),t(new a("Semaphore acquire aborted","ABORTED")),this._checkDrain(),this.schedule();}schedule(){if(this.scheduled||this.isShutdown)return;this.scheduled=true;let e=this.backoff.currentDelay;e>0?setTimeout(this._runSchedulerBound,e).unref?.():queueMicrotask(this._runSchedulerBound);}_runScheduler(){if(!this.isShutdown){this.scheduled=false;try{for(;this.queue.size>0&&!this.circuit.isOpen;){let e=this.queue.peek();if(!e||this.circuit.isHalfOpen&&e.id!==this.circuit.probeTaskId||!this.permits.hasCapacityFor(e.weight))break;let t=this.queue.pop();this.enqueueOrder.remove(t),this.enqueueOrder.size===0&&this._clearTimeout();let i=Date.now(),r=Math.max(0,i-t.enqueueTime);this.permits.acquire(t.weight),this.totalAcquired++,this.metricsCollector?.onAcquireQueued(i,r,this.permits.inFlight,this.queue.size),this.permits.assertInvariant(this.debug),t.dispatch(()=>this._createRelease(t.isProbe,t.weight))&&this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,...t.isProbe?{probe:!0}:{}});}this._checkDrain();}catch(e){e instanceof Error?console.error("[Semaphore] Scheduler error:",e.message,e.stack):console.error("[Semaphore] Scheduler error:",e);}}}_startPurgeInterval(){this.purgeIntervalId!==null&&clearInterval(this.purgeIntervalId),this.purgeIntervalId=setInterval(()=>{this.isShutdown||this._purgeStaleTasks();},this.purgeIntervalMs),this.purgeIntervalId.unref?.();}_purgeStaleTasks(){let e=Date.now(),t=this.queue.size,i=this.enqueueOrder.peekHead();for(;i!==void 0&&e-i.enqueueTime>this.queueMaxAge;){this.circuit.probeTaskId===i.id&&this.circuit.releaseProbeSlot();let r=i.discard(new a(`Task purged after ${this.queueMaxAge}ms`,"PURGED"));this._dequeue(i),r&&(this.totalTimeouts++,this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.QUEUEPURGE,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Purged stale task #${i.id}`)),i=this.enqueueOrder.peekHead();}this.debug&&this.queue.size<t&&console.info(`[Semaphore] Purged ${t-this.queue.size} stale tasks`),this.queue.size<t&&(this._checkDrain(),this.schedule());}tryAcquire(e=1){return this.isShutdown||!Number.isInteger(e)||e<1||e>this.permits.capacity||(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)?null:this._tryAcquireFast(e)}acquire(e,t=0,i=1){if(this.isShutdown)return Promise.reject(new a("Semaphore is shut down","SHUTDOWN"));if(!Number.isInteger(i)||i<1||i>this.permits.capacity)return Promise.reject(new a(`Invalid weight: ${i} (must be integer in 1..${this.permits.capacity})`,"INVALID_WEIGHT"));if(typeof t!="number"||!Number.isFinite(t))return Promise.reject(new a(`Invalid priority: ${t} (must be a finite number)`,"INVALID_PRIORITY"));if(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)return Promise.reject(new a(`Circuit breaker open, retry in ${this.circuit.cooldownRemaining}ms`,"CIRCUIT_OPEN"));if(this.circuit.isHalfOpen&&this.circuit.hasProbeInFlight)return Promise.reject(new a("Circuit breaker half-open, probe in flight","CIRCUIT_HALF_OPEN"));if(e?.aborted)return Promise.reject(new a("Semaphore acquire aborted before start","ABORTED"));this.circuit.trackAttempt();let r=this._tryAcquireFast(i);if(r)return Promise.resolve(r);let s=this.circuit.isHalfOpen&&!this.circuit.hasProbeInFlight;return !s&&this.rejectOnFull?Promise.reject(new a("Semaphore at capacity (rejectOnFull)","QUEUE_FULL")):!s&&this.queue.size>=this.queueMaxLength?Promise.reject(new a(`Queue full (${this.queueMaxLength})`,"QUEUE_FULL")):new Promise((u,c)=>{let d=++this.taskIdCounter,b=Date.now(),p=s,m=new y({id:d,priority:p?Number.MIN_SAFE_INTEGER:t,enqueueTime:b,isProbe:p,resolve:u,reject:c,abortSignal:e,weight:i});m.arm(()=>this._onTaskAbort(m,c)),p&&this.circuit.claimProbeSlot(d),this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size+1),this._enqueue(m),this.schedule();})}peekQueue(){let e=[],t=this.enqueueOrder.peekHead();for(;t!==void 0;)e.push({id:t.id,priority:t.priority,enqueueTime:t.enqueueTime,weight:t.weight,isProbe:t.isProbe}),t=t.next??void 0;return e}async use(e,t,i=0,r=1){let s=await this.acquire(t,i,r),u=this.failurePredicate!==void 0&&this.circuit.isHalfOpen;try{let c=await e();return s(),c}catch(c){if(this.failurePredicate!==void 0){let d=false;try{d=this.failurePredicate(c)===!0;}catch(b){console.warn("[Semaphore] circuitBreakerFailurePredicate threw (rejection treated as non-matching):",b);}d&&(u&&this.circuit.isHalfOpen?(this.circuit.recordFailure(),this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe operation failed")):this.reportFailure());}throw s(),c}}drain(e){return this.isShutdown?Promise.reject(new a("Cannot drain: semaphore is shut down","SHUTDOWN")):(e!==void 0&&l(e,"drain timeoutMs",1,Number.MAX_SAFE_INTEGER,true,true),this.drainPromise?this.drainPromise:this.queue.size===0&&this.permits.available===this.permits.capacity?Promise.resolve():(this.drainPromise=new Promise((t,i)=>{if(this.drainResolve=t,e!==void 0){let r=setTimeout(()=>{this.drainResolve=null,this.drainPromise=null,i(new a(`drain() timed out after ${e}ms`,"TIMEOUT"));},e),s=this.drainResolve;this.drainResolve=()=>{clearTimeout(r),s();};}}),this.drainPromise))}reset(e={}){if(this.isShutdown)throw new a("Cannot reset a semaphore that has been shut down","SHUTDOWN");for(let t of this.queue.toArray())t.discard(new a("Semaphore reset","SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this._clearTimeout(),this.metricsCollector?.reset(),this.permits.reset(),this.backoff.reset(),this.circuit.reset(),this.releaseGeneration++,this.pendingReleaseCount=0,this.scheduled=false,this.isShutdown=false,this.taskIdCounter=0,this.totalAcquired=0,this.totalReleased=0,this.totalTimeouts=0,this.totalEvictions=0,e.clearListeners&&this.eventListeners.clear(),this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this._startPurgeInterval(),this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this.debug&&console.info("[Semaphore] Reset to initial state");}shutdown(e="Semaphore shutdown"){if(!this.isShutdown){this.isShutdown=true,this.debug&&console.info(`[Semaphore] Shutdown: ${e}`),this.purgeIntervalId!==null&&(clearInterval(this.purgeIntervalId),this.purgeIntervalId=null),this._clearTimeout();for(let t of this.queue.toArray())t.discard(new a(e,"SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this.metricsCollector?.destroy(),this.metricsCollector=void 0,this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this.emit(n.SHUTDOWN,e);}}cancel(){if(this.isShutdown)return;let e=this.queue.toArray();for(let t of e)t.isProbe&&this.circuit.releaseProbeSlot(),t.discard(new a("Semaphore acquire cancelled","CANCELLED")),this._dequeue(t);this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size),this.debug&&console.info(`[Semaphore] Cancelled ${e.length} queued tasks`),this._checkDrain(),this.schedule();}reportFailure(){if(this.isShutdown)return;this.circuit.recordFailure();let e=this.circuit.evaluateAndTrip();e.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:e.timeoutRate,recentTimeouts:e.failures,total:e.attempts,reason:"reported-failure"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened via reportFailure(). Rate: ${(e.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen());}status(){let e=this.metricsCollector?.getSnapshot()??null,t=this.metricsCollector!==void 0?e?.windows?.[this.metricsCollector.primaryLabel]?.counts:void 0,i=(this.metricsCollector?.primaryWindowMs??6e4)/1e3,r=t?.acquired??0,s=t?.timeouts??0,u=this.enqueueOrder.peekHead(),c=u===void 0?0:Math.max(0,Date.now()-u.enqueueTime);return {status:{running:this.permits.capacity-this.permits.available,queued:this.queue.size,available:this.permits.available,inFlight:this.permits.inFlight,pendingReleases:this.pendingReleaseCount,circuitOpen:this.circuit.isOpen,circuitHalfOpen:this.circuit.isHalfOpen,backoffDelay:Math.round(this.backoff.currentDelay),requestsPerSecond:+(r/i).toFixed(2),timeoutRate1m:r+s>0?+(s/(r+s)*100).toFixed(1):0,queueAge:c},lifetime:{totalAcquired:this.totalAcquired,totalReleased:this.totalReleased,totalTimeouts:this.totalTimeouts,totalEvictions:this.totalEvictions,circuitBreakerCooldownRemaining:this.circuit.cooldownRemaining},metrics:e}}get availablePermits(){return this.permits.available}isAvailable(){return !this.isShutdown&&!this.circuit.isOpen&&!this.permits.isFull}get capacity(){return this.permits.capacity}get circuitState(){return this.circuit.state}get queueLength(){return this.queue.size}};var O={tripped:false},C=class{constructor(){this.state="closed";this.isOpen=false;this.isHalfOpen=false;this.hasProbeInFlight=false;this.probeTaskId=null;this.cooldownRemaining=0;}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return O}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){}};var P={tripped:false},q=class{constructor(){this.state="closed";this.hasProbeInFlight=false;this.probeTaskId=null;}get isOpen(){return this.state==="open"}get isHalfOpen(){return false}get cooldownRemaining(){return 0}open(){this.state="open";}close(){this.state="closed";}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return P}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){this.state="closed";}};exports.ManualCircuitBreaker=q;exports.NoopCircuitBreaker=C;exports.QUEUE_ORDERINGS=_;exports.SaturationCircuitBreaker=f;exports.Semaphore=M;exports.SemaphoreError=a;exports.SemaphoreEvents=n;//# sourceMappingURL=index.cjs.map
//# sourceMappingURL=index.cjs.map

@@ -66,4 +66,10 @@ interface SemaphoreConfig {

* Default: 'fifoWithPriority'
*
* Typed as `QueueOrder | (string & {})` rather than plain `QueueOrder` so a
* runtime string (e.g. from `process.env`) is assignable without a cast,
* while editors still suggest the four literal values. Anything outside the
* known set throws `INVALID_ARGUMENT` at construction — see
* `resolveComparator` in `ordering.ts`.
*/
queueOrder?: QueueOrder;
queueOrder?: QueueOrder | (string & {});
/**

@@ -424,2 +430,3 @@ * Custom comparator over queued tasks; the value that sorts lower is

private readonly windowBucketWidth;
private readonly windowBucketCount;
private readonly cooldown;

@@ -426,0 +433,0 @@ private readonly minThroughput;

@@ -66,4 +66,10 @@ interface SemaphoreConfig {

* Default: 'fifoWithPriority'
*
* Typed as `QueueOrder | (string & {})` rather than plain `QueueOrder` so a
* runtime string (e.g. from `process.env`) is assignable without a cast,
* while editors still suggest the four literal values. Anything outside the
* known set throws `INVALID_ARGUMENT` at construction — see
* `resolveComparator` in `ordering.ts`.
*/
queueOrder?: QueueOrder;
queueOrder?: QueueOrder | (string & {});
/**

@@ -424,2 +430,3 @@ * Custom comparator over queued tasks; the value that sorts lower is

private readonly windowBucketWidth;
private readonly windowBucketCount;
private readonly cooldown;

@@ -426,0 +433,0 @@ private readonly minThroughput;

@@ -1,2 +0,2 @@

var a=class extends Error{constructor(e,t){super(e),this.name="SemaphoreError",this.code=t;}};var l=(o,e,t,i,r=true,s=true)=>{if(typeof o!="number"||Number.isNaN(o))throw new a(`${e} must be a valid number`,"INVALID_ARGUMENT");if(r&&!Number.isInteger(o))throw new a(`${e} must be an integer`,"INVALID_ARGUMENT");if(s?o<t:o<=t)throw new a(`${e} must be ${s?">=":">"} ${t}`,"INVALID_ARGUMENT");if(s?o>i:o>=i)throw new a(`${e} must be ${s?"<=":"<"} ${i}`,"INVALID_ARGUMENT");return o};var w=class{constructor(e){this._inFlight=0;this.capacity=e,this._available=e;}get available(){return this._available}get inFlight(){return this._inFlight}get isFull(){return this._available===0}hasCapacityFor(e){return this._available>=e}acquire(e=1){this._available-=e,this._inFlight+=e;}release(e=1){this._available=Math.min(this._available+e,this.capacity),this._inFlight=this._inFlight<e?0:this._inFlight-e;}assertInvariant(e){if(!e)return;let t=this._inFlight+this._available;t!==this.capacity&&console.error(`[Semaphore] Invariant violation: inFlight(${this._inFlight}) + available(${this._available}) = ${t}, expected capacity(${this.capacity})`);}reset(){this._available=this.capacity,this._inFlight=0;}};var A=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=e,this.stepMs=t,this.buckets=new Int32Array(e*2),this.timestamps=new Float64Array(e);}idx(){let e=Date.now();if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs)*this.stepMs,i=Math.floor(t/this.stepMs)%this.size;return this.timestamps[i]!==t&&(this.timestamps[i]=t,this.buckets[i*2]=0,this.buckets[i*2+1]=0),this.cachedIndex=i,this.cachedUntil=t+this.stepMs,i}addAcquired(){this.buckets[this.idx()*2]++;}addTimeout(){this.buckets[this.idx()*2+1]++;}snapshot(){let e=Date.now(),t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0;for(let s=0;s<this.size;s++)this.timestamps[s]>=t&&(i+=this.buckets[s*2],r+=this.buckets[s*2+1]);return {acquired:i,timeouts:r}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.buckets.fill(0),this.timestamps.fill(0);}},f=class{constructor(e={}){this.state="closed";this.openUntil=0;this.probeInFlight=false;this._probeTaskId=null;if(this.threshold=l(e.threshold??.5,"SaturationCircuitBreaker threshold",0,1,false,false),this.window=l(e.window??1e4,"SaturationCircuitBreaker window",1e3,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketWidth=l(e.windowBucketWidth??1e3,"SaturationCircuitBreaker windowBucketWidth",1,Number.MAX_SAFE_INTEGER,true,true),this.cooldown=l(e.cooldown??5e3,"SaturationCircuitBreaker cooldown",1e3,Number.MAX_SAFE_INTEGER,true,true),this.minThroughput=l(e.minThroughput??10,"SaturationCircuitBreaker minThroughput",1,Number.MAX_SAFE_INTEGER,true,true),this.minFailures=l(e.minFailures??5,"SaturationCircuitBreaker minFailures",1,Number.MAX_SAFE_INTEGER,true,true),this.eventWindow=new A(Math.ceil(this.window/this.windowBucketWidth),this.windowBucketWidth),this.window<this.windowBucketWidth)throw new a("SaturationCircuitBreaker window must be >= windowBucketWidth","INVALID_ARGUMENT");if(this.minThroughput<this.minFailures)throw new a("SaturationCircuitBreaker minThroughput must be >= minFailures","INVALID_ARGUMENT")}get isClosed(){return this.state==="closed"}get isOpen(){return this.state==="open"}get isHalfOpen(){return this.state==="half-open"}get hasProbeInFlight(){return this.probeInFlight}get probeTaskId(){return this._probeTaskId}get cooldownRemaining(){return this.isOpen?Math.max(0,this.openUntil-Date.now()):0}trackAttempt(){this.state==="closed"&&this.eventWindow.addAcquired();}recordFailure(){this.eventWindow.addTimeout();}checkAndTransition(){return this.state!=="open"||Date.now()<this.openUntil?false:(this.state="half-open",this.probeInFlight=false,this._probeTaskId=null,true)}evaluateAndTrip(){if(this.state!=="closed")return {tripped:false};let{timeouts:e,acquired:t}=this.eventWindow.snapshot();if(t<this.minThroughput||e<this.minFailures)return {tripped:false};let i=e/t;return i<this.threshold?{tripped:false}:(this.state="open",this.openUntil=Date.now()+this.cooldown,{tripped:true,timeoutRate:i,failures:e,attempts:t})}markProbeInFlight(){this.probeInFlight=true;}claimProbeSlot(e){this.probeInFlight=true,this._probeTaskId=e;}releaseProbeSlot(){this.probeInFlight=false,this._probeTaskId=null;}handleProbeSuccess(){this.state="closed",this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}handleProbeFailure(){this.state="open",this.probeInFlight=false,this._probeTaskId=null,this.openUntil=Date.now()+this.cooldown;}reset(){this.state="closed",this.openUntil=0,this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}};var T=class{constructor(e={}){this.delay=0;this.lastTimestamp=0;if(this.initialTimeout=l(e.initialTimeout??50,"BackoffTracker initialTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.maxTimeout=l(e.maxTimeout??2e3,"BackoffTracker maxTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.decayFactor=l(e.decayFactor??.5,"BackoffTracker decayFactor",0,1,false,false),this.maxTimeout<this.initialTimeout)throw new a("BackoffTracker maxTimeout must be >= initialTimeout","INVALID_ARGUMENT")}get currentDelay(){if(this.delay===0)return 0;let e=(Date.now()-this.lastTimestamp)/1e3;if(e<=0)return this.delay;let t=this.delay*Math.pow(this.decayFactor,e);return t<1?0:t}onTimeout(){let e=this.currentDelay,t=e>0?e*2:this.initialTimeout;this.delay=Math.min(t,this.maxTimeout),this.lastTimestamp=Date.now();}reset(){this.delay=0,this.lastTimestamp=0;}};var y=class{constructor(e){this.prev=null;this.next=null;this.heapIndex=-1;this.completed=false;this.id=e.id,this.priority=e.priority,this.enqueueTime=e.enqueueTime,this.isProbe=e.isProbe,this.weight=e.weight??1,this._resolve=e.resolve,this._reject=e.reject,this.abortSignal=e.abortSignal;}arm(e){this.abortSignal&&(this.abortListener=()=>{this.claim()&&e();},this.abortSignal.addEventListener("abort",this.abortListener));}dispatch(e){return this.claim()?(this._resolve(e()),true):false}discard(e){return this.claim()?(this._reject(e),true):false}claim(){return this.completed?false:(this.completed=true,this.abortSignal&&this.abortListener&&this.abortSignal.removeEventListener("abort",this.abortListener),true)}reject(e){this._reject(e);}};var S=class{constructor(e){this.heap=[];this.compare=e;}get size(){return this.heap.length}isEmpty(){return this.heap.length===0}peek(){return this.heap[0]}toArray(){return [...this.heap]}has(e){return e.heapIndex>=0&&this.heap[e.heapIndex]===e}clear(){for(let e of this.heap)e.heapIndex=-1;this.heap=[];}insert(e){if(e.heapIndex>=0)throw new a("Item is already in a heap","INVALID_ARGUMENT");let t=this.heap.length;this.heap.push(e),e.heapIndex=t,this._bubbleUp(t);}pop(){if(this.heap.length===0)return;let e=this.heap[0];e.heapIndex=-1;let t=this.heap.pop();return this.heap.length>0&&t!==e&&(this.heap[0]=t,t.heapIndex=0,this._bubbleDown(0)),e}delete(e){let t=e.heapIndex;if(t<0||this.heap[t]!==e)return;e.heapIndex=-1;let i=this.heap.pop();if(t===this.heap.length||i===e)return e;this.heap[t]=i,i.heapIndex=t;let r=this.heap[t-1>>1];return t>0&&this.compare(i,r)<0?this._bubbleUp(t):this._bubbleDown(t),e}_swap(e,t){let i=this.heap[e],r=this.heap[t];this.heap[e]=r,this.heap[t]=i,i.heapIndex=t,r.heapIndex=e;}_bubbleUp(e){for(;e>0;){let t=e-1>>1;if(this.compare(this.heap[e],this.heap[t])<0)this._swap(e,t),e=t;else break}}_bubbleDown(e){let t=this.heap.length;for(;;){let i=e,r=2*e+1,s=2*e+2;if(r<t&&this.compare(this.heap[r],this.heap[i])<0&&(i=r),s<t&&this.compare(this.heap[s],this.heap[i])<0&&(i=s),i===e)break;this._swap(e,i),e=i;}}};var I=class{constructor(){this.head=null;this.tail=null;this._size=0;}get size(){return this._size}isEmpty(){return this._size===0}peekHead(){return this.head===null?void 0:this.head}pushTail(e){e.prev=this.tail,e.next=null,this.tail!==null?this.tail.next=e:this.head=e,this.tail=e,this._size++;}remove(e){e.prev!==null?e.prev.next=e.next:this.head=e.next,e.next!==null?e.next.prev=e.prev:this.tail=e.prev,e.prev=e.next=null,this._size--;}clear(){this.head=this.tail=null,this._size=0;}};var E=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=l(e,"CombinedWindow size",1,Number.MAX_SAFE_INTEGER,true,true),this.stepMs=l(t,"CombinedWindow stepMs",1,Number.MAX_SAFE_INTEGER,true,true),this.timestamps=new Float64Array(e),this.acquired=new Int32Array(e),this.released=new Int32Array(e),this.timeouts=new Int32Array(e),this.ifSum=new Float64Array(e),this.ifCount=new Int32Array(e),this.ifMax=new Float64Array(e),this.qSum=new Float64Array(e),this.qCount=new Int32Array(e),this.qMax=new Float64Array(e),this.latSum=new Float64Array(e),this.latCount=new Int32Array(e);}bucket(e){if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs),i=t*this.stepMs,r=t%this.size;return this.timestamps[r]!==i&&(this.timestamps[r]=i,this.acquired[r]=0,this.released[r]=0,this.timeouts[r]=0,this.ifSum[r]=0,this.ifCount[r]=0,this.ifMax[r]=0,this.qSum[r]=0,this.qCount[r]=0,this.qMax[r]=0,this.latSum[r]=0,this.latCount[r]=0),this.cachedIndex=r,this.cachedUntil=i+this.stepMs,r}addInflight(e,t){this.ifSum[e]+=t,this.ifCount[e]++,t>this.ifMax[e]&&(this.ifMax[e]=t);}addQueue(e,t){this.qSum[e]+=t,this.qCount[e]++,t>this.qMax[e]&&(this.qMax[e]=t);}recordAcquire(e,t,i){let r=this.bucket(e);this.acquired[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordAcquireQueued(e,t,i,r){let s=this.bucket(e);this.acquired[s]++,this.latSum[s]+=t,this.latCount[s]++,this.addInflight(s,i),this.addQueue(s,r);}recordRelease(e,t,i){let r=this.bucket(e);this.released[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordTimeoutQueue(e,t){let i=this.bucket(e);this.timeouts[i]++,this.addQueue(i,t);}sampleBoth(e,t,i){let r=this.bucket(e);this.addInflight(r,t),this.addQueue(r,i);}addAcquired(e){this.acquired[this.bucket(e)]++;}addReleased(e){this.released[this.bucket(e)]++;}addTimeout(e){this.timeouts[this.bucket(e)]++;}addLatency(e,t){let i=this.bucket(e);this.latSum[i]+=t,this.latCount[i]++;}sampleInflight(e,t){this.addInflight(this.bucket(e),t);}sampleQueue(e,t){this.addQueue(this.bucket(e),t);}snapshot(e){let t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0,s=0,u=0,c=0,d=0,b=0,p=0,m=0,C=0,v=0;for(let h=0;h<this.size;h++)this.timestamps[h]<t||(i+=this.acquired[h],r+=this.released[h],s+=this.timeouts[h],u+=this.ifSum[h],c+=this.ifCount[h],this.ifMax[h]>d&&(d=this.ifMax[h]),b+=this.qSum[h],p+=this.qCount[h],this.qMax[h]>m&&(m=this.qMax[h]),C+=this.latSum[h],v+=this.latCount[h]);return {counts:{acquired:i,released:r,timeouts:s},inflight:{avg:c===0?0:u/c,max:d,samples:c},queue:{avg:p===0?0:b/p,max:m,samples:p},latency:{avg:v===0?0:C/v,count:v,total:C}}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.timestamps.fill(0),this.acquired.fill(0),this.released.fill(0),this.timeouts.fill(0),this.ifSum.fill(0),this.ifCount.fill(0),this.ifMax.fill(0),this.qSum.fill(0),this.qCount.fill(0),this.qMax.fill(0),this.latSum.fill(0),this.latCount.fill(0);}},R=[{size:60,stepMs:1e3},{size:60,stepMs:5e3},{size:60,stepMs:15e3},{size:60,stepMs:6e4},{size:60,stepMs:144e4}],k=class{constructor(e=R){this._totalAcquiredFast=0;this._totalAcquiredQueued=0;this._totalReleased=0;this._totalTimeouts=0;this._totalAborts=0;this._capacity=0;this._circuitOpen=false;this._circuitHalfOpen=false;if(e.length===0)throw new a("SemaphoreMetrics requires at least one WindowOptions","INVALID_ARGUMENT");this.windows=e.map(({size:r,stepMs:s})=>new E(r,s)),this.windowLabels=e.map(({size:r,stepMs:s})=>{let u=r*s;return u>=36e5&&u%36e5===0?`${u/36e5}h`:u>=6e4&&u%6e4===0?`${u/6e4}m`:u>=1e3&&u%1e3===0?`${u/1e3}s`:`${u}ms`});let t=new Set;for(let r of this.windowLabels){if(t.has(r))throw new a(`SemaphoreMetrics windows produce duplicate label "${r}" (two windows cover the same horizon)`,"INVALID_ARGUMENT");t.add(r);}let i=0;for(let r=1;r<e.length;r++)e[r].size*e[r].stepMs<e[i].size*e[i].stepMs&&(i=r);this.primaryLabel=this.windowLabels[i],this.primaryWindowMs=e[i].size*e[i].stepMs;}onAcquireFast(e,t,i){this._totalAcquiredFast++;for(let r of this.windows)r.recordAcquire(e,t,i);}onAcquireQueued(e,t,i,r){this._totalAcquiredQueued++;for(let s of this.windows)s.recordAcquireQueued(e,t,i,r);}onRelease(e,t,i){this._totalReleased++;for(let r of this.windows)r.recordRelease(e,t,i);}onTimeout(e,t){this._totalTimeouts++;for(let i of this.windows)i.recordTimeoutQueue(e,t);}onAbort(e,t){this._totalAborts++;for(let i of this.windows)i.sampleQueue(e,t);}sampleGauges(e,t,i){for(let r of this.windows)r.sampleBoth(e,t,i);}sampleQueueDepthAt(e,t){for(let i of this.windows)i.sampleQueue(e,t);}markAcquireFast(){this._totalAcquiredFast++;let e=Date.now();for(let t of this.windows)t.addAcquired(e);}markAcquireQueued(e){this._totalAcquiredQueued++;let t=Date.now();for(let i of this.windows)i.addAcquired(t),i.addLatency(t,e);}markReleased(){this._totalReleased++;let e=Date.now();for(let t of this.windows)t.addReleased(e);}markTimeout(){this._totalTimeouts++;let e=Date.now();for(let t of this.windows)t.addTimeout(e);}markAbort(){this._totalAborts++;}sampleInFlight(e){let t=Date.now();for(let i of this.windows)i.sampleInflight(t,e);}sampleQueueDepth(e){let t=Date.now();for(let i of this.windows)i.sampleQueue(t,e);}markCapacityChange(e){this._capacity=e;}markCircuitOpen(){this._circuitOpen=true,this._circuitHalfOpen=false;}markCircuitHalfOpen(){this._circuitOpen=false,this._circuitHalfOpen=true;}markCircuitClose(){this._circuitOpen=false,this._circuitHalfOpen=false;}getSnapshot(){let e=Date.now(),t={},i=0,r=0;for(let s=0;s<this.windowLabels.length;s++){let u=this.windows[s].snapshot(e);t[this.windowLabels[s]]=u,s===0&&(i=u.inflight.avg,r=u.queue.avg);}return {windows:t,meta:{inFlightLastMinute:Math.round(i),queueDepthLastMinute:Math.round(r),totalAcquiredFast:this._totalAcquiredFast,totalAcquiredQueued:this._totalAcquiredQueued,totalReleased:this._totalReleased,totalTimeouts:this._totalTimeouts,totalAborts:this._totalAborts,capacity:this._capacity,circuitOpen:this._circuitOpen,circuitHalfOpen:this._circuitHalfOpen}}}reset(){for(let e of this.windows)e.reset();this._totalAcquiredFast=0,this._totalAcquiredQueued=0,this._totalReleased=0,this._totalTimeouts=0,this._totalAborts=0,this._capacity=0,this._circuitOpen=false,this._circuitHalfOpen=false;}destroy(){this.reset();}};var _={fifo:(o,e)=>o.id-e.id,lifo:(o,e)=>e.id-o.id,fifoWithPriority:(o,e)=>o.priority-e.priority||o.id-e.id,lifoWithPriority:(o,e)=>o.priority-e.priority||e.id-o.id};function x(o){if(o.comparator!==void 0){if(typeof o.comparator!="function")throw new a("Semaphore comparator must be a function","INVALID_ARGUMENT");return o.comparator}let e=o.queueOrder??"fifoWithPriority",t=_[e];if(t===void 0)throw new a(`Semaphore queueOrder must be one of: ${Object.keys(_).join(", ")} (got ${JSON.stringify(e)})`,"INVALID_ARGUMENT");return t}function F(o){let e=x(o);return (t,i)=>{if(t.isProbe!==i.isProbe)return t.isProbe?-1:1;let r=e(t,i);return typeof r!="number"||Number.isNaN(r)?t.id-i.id:r}}var n={TASKACQUIRE:"task-acquire",TASKRELEASE:"task-release",TASKTIMEOUT:"task-timeout",TASKABORT:"task-abort",QUEUEPURGE:"queue-purge",QUEUEEVICT:"queue-evict",CIRCUITOPEN:"circuit-open",CIRCUITHALFOPEN:"circuit-half-open",CIRCUITCLOSE:"circuit-close",SHUTDOWN:"shutdown"};var M=class{constructor(e,t={}){this.pendingReleaseCount=0;this.releaseGeneration=0;this.scheduled=false;this.isShutdown=false;this.taskIdCounter=0;this.totalAcquired=0;this.totalReleased=0;this.totalTimeouts=0;this.totalEvictions=0;this.eventListeners=new Map;this.drainPromise=null;this.drainResolve=null;this.purgeIntervalId=null;this.timeoutTimerId=null;this._runSchedulerBound=()=>{this._runScheduler();};if(l(e,"Semaphore count",0,Number.MAX_SAFE_INTEGER,true,false),this.purgeIntervalMs=l(t.purgeIntervalMs??3e3,"Semaphore purgeIntervalMs",500,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxTimeout=l(t.queueMaxTimeout??1e4,"Semaphore queueMaxTimeout",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxLength=l(t.queueMaxLength??1024,"Semaphore queueMaxLength",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxAge=l(t.queueMaxAge??3e4,"Semaphore queueMaxAge",1,Number.MAX_SAFE_INTEGER,true,true),this.rejectOnFull=t.rejectOnFull??false,this.metricsEnabled=t.metricsEnabled??true,this.debug=t.debug??false,t.circuitBreakerFailurePredicate!==void 0&&typeof t.circuitBreakerFailurePredicate!="function")throw new a("Semaphore circuitBreakerFailurePredicate must be a function","INVALID_ARGUMENT");this.failurePredicate=t.circuitBreakerFailurePredicate;let i=F({queueOrder:t.queueOrder,comparator:t.comparator});this.queue=new S(i),this.enqueueOrder=new I,this.permits=new w(e),this.circuit=t.circuitBreaker??new f({threshold:t.circuitBreakerThreshold,window:t.circuitBreakerWindow,windowBucketWidth:t.circuitBreakerWindowBucketWidth,cooldown:t.circuitBreakerCooldown,minThroughput:t.circuitBreakerMinThroughput,minFailures:t.circuitBreakerMinFailures}),this.backoff=new T({initialTimeout:t.backoffInitialTimeout,maxTimeout:t.backoffMaxTimeout,decayFactor:t.backoffDecayFactor}),this.metricsCollector=this.metricsEnabled?new k(t.metricsWindows):void 0,this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this._startPurgeInterval();}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){this.eventListeners.get(e)?.delete(t),this.eventListeners.get(e)?.size===0&&this.eventListeners.delete(e);}removeAllListeners(e){e?this.eventListeners.delete(e):this.eventListeners.clear();}hasListeners(e){let t=this.eventListeners.get(e);return t!==void 0&&t.size>0}emit(e,...t){let i=this.eventListeners.get(e);if(!(!i||i.size===0)){if(i.size===1){let r=i.values().next().value;try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}return}for(let r of Array.from(i))try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}}}_tryAcquireFast(e){return this.circuit.isHalfOpen?this.circuit.hasProbeInFlight||!this.permits.hasCapacityFor(e)?null:(this.circuit.markProbeInFlight(),this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,probe:true}),this._createRelease(true,e)):this.queue.size>0||!this.permits.hasCapacityFor(e)?null:(this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._createRelease(false,e))}_createRelease(e=false,t=1){this.pendingReleaseCount++;let i=this.releaseGeneration,r=false;return ()=>{if(r||i!==this.releaseGeneration){this.debug&&console.warn("[Semaphore] release() called after already released (no-op)");return}r=true,this.pendingReleaseCount--,this.permits.release(t),this.totalReleased++,this.metricsCollector?.onRelease(Date.now(),this.permits.inFlight,this.queue.size),e&&this.circuit.isHalfOpen&&(this.circuit.handleProbeSuccess(),this.emit(n.CIRCUITCLOSE),this.metricsCollector?.markCircuitClose(),this.debug&&console.info("[Semaphore] Circuit closed after successful probe")),this.permits.assertInvariant(this.debug),this.hasListeners(n.TASKRELEASE)&&this.emit(n.TASKRELEASE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._checkDrain(),this.schedule();}}_checkDrain(){this.drainResolve&&this.queue.size===0&&this.permits.available===this.permits.capacity&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null);}_enqueue(e){this.queue.insert(e),this.enqueueOrder.pushTail(e),this._armTimeout();}_dequeue(e){this.queue.delete(e)!==void 0&&(this.enqueueOrder.remove(e),this.enqueueOrder.size===0&&this._clearTimeout());}_armTimeout(){if(this.timeoutTimerId!==null)return;let e=this.enqueueOrder.peekHead();if(e===void 0)return;let t=Math.max(0,e.enqueueTime+this.queueMaxTimeout-Date.now());this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),t);}_clearTimeout(){this.timeoutTimerId!==null&&(clearTimeout(this.timeoutTimerId),this.timeoutTimerId=null);}_fireTimeout(){if(this.timeoutTimerId=null,this.isShutdown)return;let e=Date.now(),t=0,i=this.enqueueOrder.peekHead();for(;i!==void 0&&i.enqueueTime+this.queueMaxTimeout<=e;){let r=i.claim();this._dequeue(i),r&&(this._timeoutTask(i),t++),i=this.enqueueOrder.peekHead();}if(i!==void 0){let r=Math.max(0,i.enqueueTime+this.queueMaxTimeout-e);this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),r);}t>0&&(this._checkDrain(),this.schedule());}_evictQueueOnCircuitOpen(e){if(this.queue.size===0)return;let t=0;for(let i of this.queue.toArray()){if(i===e||i.isProbe)continue;let r=i.discard(new a("Circuit breaker opened while task was queued","CIRCUIT_OPEN"));this._dequeue(i),r&&(t++,this.totalEvictions++,this.emit(n.QUEUEEVICT,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Evicted queued task #${i.id}: circuit opened`));}t>0&&this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size);}_timeoutTask(e){if(this.totalTimeouts++,this.circuit.recordFailure(),this.backoff.onTimeout(),e.isProbe)this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe timed out");else {let t=this.circuit.evaluateAndTrip();t.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:t.timeoutRate,recentTimeouts:t.failures,total:t.attempts}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened. Rate: ${(t.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen(e));}this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.TASKTIMEOUT,{queueLength:this.queue.size,backoffDelay:this.backoff.currentDelay,taskId:e.id}),this.debug&&console.warn(`[Semaphore] Task #${e.id} timed out after ${this.queueMaxTimeout}ms`),e.reject(new a(`Semaphore acquire timed out after ${this.queueMaxTimeout}ms (queue: ${this.queue.size})`,"TIMEOUT"));}_onTaskAbort(e,t){this._dequeue(e),e.isProbe&&this.circuit.releaseProbeSlot(),this.metricsCollector?.onAbort(Date.now(),this.queue.size),this.emit(n.TASKABORT),this.debug&&console.info(`[Semaphore] Task #${e.id} aborted`),t(new a("Semaphore acquire aborted","ABORTED")),this._checkDrain(),this.schedule();}schedule(){if(this.scheduled||this.isShutdown)return;this.scheduled=true;let e=this.backoff.currentDelay;e>0?setTimeout(this._runSchedulerBound,e).unref?.():queueMicrotask(this._runSchedulerBound);}_runScheduler(){if(!this.isShutdown){this.scheduled=false;try{for(;this.queue.size>0&&!this.circuit.isOpen;){let e=this.queue.peek();if(!e||this.circuit.isHalfOpen&&e.id!==this.circuit.probeTaskId||!this.permits.hasCapacityFor(e.weight))break;let t=this.queue.pop();this.enqueueOrder.remove(t),this.enqueueOrder.size===0&&this._clearTimeout();let i=Date.now(),r=Math.max(0,i-t.enqueueTime);this.permits.acquire(t.weight),this.totalAcquired++,this.metricsCollector?.onAcquireQueued(i,r,this.permits.inFlight,this.queue.size),this.permits.assertInvariant(this.debug),t.dispatch(()=>this._createRelease(t.isProbe,t.weight))&&this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,...t.isProbe?{probe:!0}:{}});}this._checkDrain();}catch(e){e instanceof Error?console.error("[Semaphore] Scheduler error:",e.message,e.stack):console.error("[Semaphore] Scheduler error:",e);}}}_startPurgeInterval(){this.purgeIntervalId!==null&&clearInterval(this.purgeIntervalId),this.purgeIntervalId=setInterval(()=>{this.isShutdown||this._purgeStaleTasks();},this.purgeIntervalMs),this.purgeIntervalId.unref?.();}_purgeStaleTasks(){let e=Date.now(),t=this.queue.size,i=this.enqueueOrder.peekHead();for(;i!==void 0&&e-i.enqueueTime>this.queueMaxAge;){this.circuit.probeTaskId===i.id&&this.circuit.releaseProbeSlot();let r=i.discard(new a(`Task purged after ${this.queueMaxAge}ms`,"PURGED"));this._dequeue(i),r&&(this.totalTimeouts++,this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.QUEUEPURGE,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Purged stale task #${i.id}`)),i=this.enqueueOrder.peekHead();}this.debug&&this.queue.size<t&&console.info(`[Semaphore] Purged ${t-this.queue.size} stale tasks`),this.queue.size<t&&(this._checkDrain(),this.schedule());}tryAcquire(e=1){return this.isShutdown||!Number.isInteger(e)||e<1||e>this.permits.capacity||(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)?null:this._tryAcquireFast(e)}acquire(e,t=0,i=1){if(this.isShutdown)return Promise.reject(new a("Semaphore is shut down","SHUTDOWN"));if(!Number.isInteger(i)||i<1||i>this.permits.capacity)return Promise.reject(new a(`Invalid weight: ${i} (must be integer in 1..${this.permits.capacity})`,"INVALID_WEIGHT"));if(typeof t!="number"||!Number.isFinite(t))return Promise.reject(new a(`Invalid priority: ${t} (must be a finite number)`,"INVALID_PRIORITY"));if(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)return Promise.reject(new a(`Circuit breaker open, retry in ${this.circuit.cooldownRemaining}ms`,"CIRCUIT_OPEN"));if(this.circuit.isHalfOpen&&this.circuit.hasProbeInFlight)return Promise.reject(new a("Circuit breaker half-open, probe in flight","CIRCUIT_HALF_OPEN"));if(e?.aborted)return Promise.reject(new a("Semaphore acquire aborted before start","ABORTED"));this.circuit.trackAttempt();let r=this._tryAcquireFast(i);if(r)return Promise.resolve(r);let s=this.circuit.isHalfOpen&&!this.circuit.hasProbeInFlight;return !s&&this.rejectOnFull?Promise.reject(new a("Semaphore at capacity (rejectOnFull)","QUEUE_FULL")):!s&&this.queue.size>=this.queueMaxLength?Promise.reject(new a(`Queue full (${this.queueMaxLength})`,"QUEUE_FULL")):new Promise((u,c)=>{let d=++this.taskIdCounter,b=Date.now(),p=s,m=new y({id:d,priority:p?Number.MIN_SAFE_INTEGER:t,enqueueTime:b,isProbe:p,resolve:u,reject:c,abortSignal:e,weight:i});m.arm(()=>this._onTaskAbort(m,c)),p&&this.circuit.claimProbeSlot(d),this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size+1),this._enqueue(m),this.schedule();})}peekQueue(){let e=[],t=this.enqueueOrder.peekHead();for(;t!==void 0;)e.push({id:t.id,priority:t.priority,enqueueTime:t.enqueueTime,weight:t.weight,isProbe:t.isProbe}),t=t.next??void 0;return e}async use(e,t,i=0,r=1){let s=await this.acquire(t,i,r),u=this.failurePredicate!==void 0&&this.circuit.isHalfOpen;try{let c=await e();return s(),c}catch(c){if(this.failurePredicate!==void 0){let d=false;try{d=this.failurePredicate(c)===!0;}catch(b){console.warn("[Semaphore] circuitBreakerFailurePredicate threw (rejection treated as non-matching):",b);}d&&(u&&this.circuit.isHalfOpen?(this.circuit.recordFailure(),this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe operation failed")):this.reportFailure());}throw s(),c}}drain(e){return this.isShutdown?Promise.reject(new a("Cannot drain: semaphore is shut down","SHUTDOWN")):(e!==void 0&&l(e,"drain timeoutMs",1,Number.MAX_SAFE_INTEGER,true,true),this.drainPromise?this.drainPromise:this.queue.size===0&&this.permits.available===this.permits.capacity?Promise.resolve():(this.drainPromise=new Promise((t,i)=>{if(this.drainResolve=t,e!==void 0){let r=setTimeout(()=>{this.drainResolve=null,this.drainPromise=null,i(new a(`drain() timed out after ${e}ms`,"TIMEOUT"));},e),s=this.drainResolve;this.drainResolve=()=>{clearTimeout(r),s();};}}),this.drainPromise))}reset(e={}){if(this.isShutdown)throw new a("Cannot reset a semaphore that has been shut down","SHUTDOWN");for(let t of this.queue.toArray())t.discard(new a("Semaphore reset","SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this._clearTimeout(),this.metricsCollector?.reset(),this.permits.reset(),this.backoff.reset(),this.circuit.reset(),this.releaseGeneration++,this.pendingReleaseCount=0,this.scheduled=false,this.isShutdown=false,this.taskIdCounter=0,this.totalAcquired=0,this.totalReleased=0,this.totalTimeouts=0,this.totalEvictions=0,e.clearListeners&&this.eventListeners.clear(),this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this._startPurgeInterval(),this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this.debug&&console.info("[Semaphore] Reset to initial state");}shutdown(e="Semaphore shutdown"){if(!this.isShutdown){this.isShutdown=true,this.debug&&console.info(`[Semaphore] Shutdown: ${e}`),this.purgeIntervalId!==null&&(clearInterval(this.purgeIntervalId),this.purgeIntervalId=null),this._clearTimeout();for(let t of this.queue.toArray())t.discard(new a(e,"SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this.metricsCollector?.destroy(),this.metricsCollector=void 0,this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this.emit(n.SHUTDOWN,e);}}cancel(){if(this.isShutdown)return;let e=this.queue.toArray();for(let t of e)t.isProbe&&this.circuit.releaseProbeSlot(),t.discard(new a("Semaphore acquire cancelled","CANCELLED")),this._dequeue(t);this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size),this.debug&&console.info(`[Semaphore] Cancelled ${e.length} queued tasks`),this._checkDrain(),this.schedule();}reportFailure(){if(this.isShutdown)return;this.circuit.recordFailure();let e=this.circuit.evaluateAndTrip();e.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:e.timeoutRate,recentTimeouts:e.failures,total:e.attempts,reason:"reported-failure"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened via reportFailure(). Rate: ${(e.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen());}status(){let e=this.metricsCollector?.getSnapshot()??null,t=this.metricsCollector!==void 0?e?.windows?.[this.metricsCollector.primaryLabel]?.counts:void 0,i=(this.metricsCollector?.primaryWindowMs??6e4)/1e3,r=t?.acquired??0,s=t?.timeouts??0,u=this.enqueueOrder.peekHead(),c=u===void 0?0:Math.max(0,Date.now()-u.enqueueTime);return {status:{running:this.permits.capacity-this.permits.available,queued:this.queue.size,available:this.permits.available,inFlight:this.permits.inFlight,pendingReleases:this.pendingReleaseCount,circuitOpen:this.circuit.isOpen,circuitHalfOpen:this.circuit.isHalfOpen,backoffDelay:Math.round(this.backoff.currentDelay),requestsPerSecond:+(r/i).toFixed(2),timeoutRate1m:r+s>0?+(s/(r+s)*100).toFixed(1):0,queueAge:c},lifetime:{totalAcquired:this.totalAcquired,totalReleased:this.totalReleased,totalTimeouts:this.totalTimeouts,totalEvictions:this.totalEvictions,circuitBreakerCooldownRemaining:this.circuit.cooldownRemaining},metrics:e}}get availablePermits(){return this.permits.available}isAvailable(){return !this.isShutdown&&!this.circuit.isOpen&&!this.permits.isFull}get capacity(){return this.permits.capacity}get circuitState(){return this.circuit.state}get queueLength(){return this.queue.size}};var O={tripped:false},q=class{constructor(){this.state="closed";this.isOpen=false;this.isHalfOpen=false;this.hasProbeInFlight=false;this.probeTaskId=null;this.cooldownRemaining=0;}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return O}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){}};var P={tripped:false},g=class{constructor(){this.state="closed";this.hasProbeInFlight=false;this.probeTaskId=null;}get isOpen(){return this.state==="open"}get isHalfOpen(){return false}get cooldownRemaining(){return 0}open(){this.state="open";}close(){this.state="closed";}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return P}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){this.state="closed";}};export{g as ManualCircuitBreaker,q as NoopCircuitBreaker,_ as QUEUE_ORDERINGS,f as SaturationCircuitBreaker,M as Semaphore,a as SemaphoreError,n as SemaphoreEvents};//# sourceMappingURL=index.js.map
var a=class extends Error{constructor(e,t){super(e),this.name="SemaphoreError",this.code=t;}};var l=(o,e,t,i,r=true,s=true)=>{if(typeof o!="number"||Number.isNaN(o))throw new a(`${e} must be a valid number`,"INVALID_ARGUMENT");if(r&&!Number.isInteger(o))throw new a(`${e} must be an integer`,"INVALID_ARGUMENT");if(s?o<t:o<=t)throw new a(`${e} must be ${s?">=":">"} ${t}`,"INVALID_ARGUMENT");if(s?o>i:o>=i)throw new a(`${e} must be ${s?"<=":"<"} ${i}`,"INVALID_ARGUMENT");return o};var w=class{constructor(e){this._inFlight=0;this.capacity=e,this._available=e;}get available(){return this._available}get inFlight(){return this._inFlight}get isFull(){return this._available===0}hasCapacityFor(e){return this._available>=e}acquire(e=1){this._available-=e,this._inFlight+=e;}release(e=1){this._available=Math.min(this._available+e,this.capacity),this._inFlight=this._inFlight<e?0:this._inFlight-e;}assertInvariant(e){if(!e)return;let t=this._inFlight+this._available;t!==this.capacity&&console.error(`[Semaphore] Invariant violation: inFlight(${this._inFlight}) + available(${this._available}) = ${t}, expected capacity(${this.capacity})`);}reset(){this._available=this.capacity,this._inFlight=0;}};var A=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=e,this.stepMs=t,this.buckets=new Int32Array(e*2),this.timestamps=new Float64Array(e);}idx(){let e=Date.now();if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs)*this.stepMs,i=Math.floor(t/this.stepMs)%this.size;return this.timestamps[i]!==t&&(this.timestamps[i]=t,this.buckets[i*2]=0,this.buckets[i*2+1]=0),this.cachedIndex=i,this.cachedUntil=t+this.stepMs,i}addAcquired(){this.buckets[this.idx()*2]++;}addTimeout(){this.buckets[this.idx()*2+1]++;}snapshot(){let e=Date.now(),t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0;for(let s=0;s<this.size;s++)this.timestamps[s]>=t&&(i+=this.buckets[s*2],r+=this.buckets[s*2+1]);return {acquired:i,timeouts:r}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.buckets.fill(0),this.timestamps.fill(0);}},f=class{constructor(e={}){this.state="closed";this.openUntil=0;this.probeInFlight=false;this._probeTaskId=null;if(this.threshold=l(e.threshold??.5,"SaturationCircuitBreaker threshold",0,1,false,false),this.window=l(e.window??1e4,"SaturationCircuitBreaker window",1e3,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketWidth=l(e.windowBucketWidth??1e3,"SaturationCircuitBreaker windowBucketWidth",1,Number.MAX_SAFE_INTEGER,true,true),this.windowBucketCount=Math.ceil(this.window/this.windowBucketWidth),this.cooldown=l(e.cooldown??5e3,"SaturationCircuitBreaker cooldown",1e3,Number.MAX_SAFE_INTEGER,true,true),this.minThroughput=l(e.minThroughput??10,"SaturationCircuitBreaker minThroughput",1,Number.MAX_SAFE_INTEGER,true,true),this.minFailures=l(e.minFailures??5,"SaturationCircuitBreaker minFailures",1,Number.MAX_SAFE_INTEGER,true,true),this.window<this.windowBucketWidth)throw new a("SaturationCircuitBreaker window must be >= windowBucketWidth","INVALID_ARGUMENT");if(this.minThroughput<this.minFailures)throw new a("SaturationCircuitBreaker minThroughput must be >= minFailures","INVALID_ARGUMENT");if(this.windowBucketCount<2)throw new a("SaturationCircuitBreaker window must span at least 2 windowBucketWidth buckets","INVALID_ARGUMENT");this.eventWindow=new A(this.windowBucketCount,this.windowBucketWidth);}get isClosed(){return this.state==="closed"}get isOpen(){return this.state==="open"}get isHalfOpen(){return this.state==="half-open"}get hasProbeInFlight(){return this.probeInFlight}get probeTaskId(){return this._probeTaskId}get cooldownRemaining(){return this.isOpen?Math.max(0,this.openUntil-Date.now()):0}trackAttempt(){this.state==="closed"&&this.eventWindow.addAcquired();}recordFailure(){this.eventWindow.addTimeout();}checkAndTransition(){return this.state!=="open"||Date.now()<this.openUntil?false:(this.state="half-open",this.probeInFlight=false,this._probeTaskId=null,true)}evaluateAndTrip(){if(this.state!=="closed")return {tripped:false};let{timeouts:e,acquired:t}=this.eventWindow.snapshot();if(t<this.minThroughput||e<this.minFailures)return {tripped:false};let i=e/t;return i<this.threshold?{tripped:false}:(this.state="open",this.openUntil=Date.now()+this.cooldown,{tripped:true,timeoutRate:i,failures:e,attempts:t})}markProbeInFlight(){this.probeInFlight=true;}claimProbeSlot(e){this.probeInFlight=true,this._probeTaskId=e;}releaseProbeSlot(){this.probeInFlight=false,this._probeTaskId=null;}handleProbeSuccess(){this.state="closed",this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}handleProbeFailure(){this.state="open",this.probeInFlight=false,this._probeTaskId=null,this.openUntil=Date.now()+this.cooldown;}reset(){this.state="closed",this.openUntil=0,this.probeInFlight=false,this._probeTaskId=null,this.eventWindow.reset();}};var T=class{constructor(e={}){this.delay=0;this.lastTimestamp=0;if(this.initialTimeout=l(e.initialTimeout??50,"BackoffTracker initialTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.maxTimeout=l(e.maxTimeout??2e3,"BackoffTracker maxTimeout",0,Number.MAX_SAFE_INTEGER,true,true),this.decayFactor=l(e.decayFactor??.5,"BackoffTracker decayFactor",0,1,false,false),this.maxTimeout<this.initialTimeout)throw new a("BackoffTracker maxTimeout must be >= initialTimeout","INVALID_ARGUMENT")}get currentDelay(){if(this.delay===0)return 0;let e=(Date.now()-this.lastTimestamp)/1e3;if(e<=0)return this.delay;let t=this.delay*Math.pow(this.decayFactor,e);return t<1?0:t}onTimeout(){let e=this.currentDelay,t=e>0?e*2:this.initialTimeout;this.delay=Math.min(t,this.maxTimeout),this.lastTimestamp=Date.now();}reset(){this.delay=0,this.lastTimestamp=0;}};var y=class{constructor(e){this.prev=null;this.next=null;this.heapIndex=-1;this.completed=false;this.id=e.id,this.priority=e.priority,this.enqueueTime=e.enqueueTime,this.isProbe=e.isProbe,this.weight=e.weight??1,this._resolve=e.resolve,this._reject=e.reject,this.abortSignal=e.abortSignal;}arm(e){this.abortSignal&&(this.abortListener=()=>{this.claim()&&e();},this.abortSignal.addEventListener("abort",this.abortListener));}dispatch(e){return this.claim()?(this._resolve(e()),true):false}discard(e){return this.claim()?(this._reject(e),true):false}claim(){return this.completed?false:(this.completed=true,this.abortSignal&&this.abortListener&&this.abortSignal.removeEventListener("abort",this.abortListener),true)}reject(e){this._reject(e);}};var S=class{constructor(e){this.heap=[];this.compare=e;}get size(){return this.heap.length}isEmpty(){return this.heap.length===0}peek(){return this.heap[0]}toArray(){return [...this.heap]}has(e){return e.heapIndex>=0&&this.heap[e.heapIndex]===e}clear(){for(let e of this.heap)e.heapIndex=-1;this.heap=[];}insert(e){if(e.heapIndex>=0)throw new a("Item is already in a heap","INVALID_ARGUMENT");let t=this.heap.length;this.heap.push(e),e.heapIndex=t,this._bubbleUp(t);}pop(){if(this.heap.length===0)return;let e=this.heap[0];e.heapIndex=-1;let t=this.heap.pop();return this.heap.length>0&&t!==e&&(this.heap[0]=t,t.heapIndex=0,this._bubbleDown(0)),e}delete(e){let t=e.heapIndex;if(t<0||this.heap[t]!==e)return;e.heapIndex=-1;let i=this.heap.pop();if(t===this.heap.length||i===e)return e;this.heap[t]=i,i.heapIndex=t;let r=this.heap[t-1>>1];return t>0&&this.compare(i,r)<0?this._bubbleUp(t):this._bubbleDown(t),e}_swap(e,t){let i=this.heap[e],r=this.heap[t];this.heap[e]=r,this.heap[t]=i,i.heapIndex=t,r.heapIndex=e;}_bubbleUp(e){for(;e>0;){let t=e-1>>1;if(this.compare(this.heap[e],this.heap[t])<0)this._swap(e,t),e=t;else break}}_bubbleDown(e){let t=this.heap.length;for(;;){let i=e,r=2*e+1,s=2*e+2;if(r<t&&this.compare(this.heap[r],this.heap[i])<0&&(i=r),s<t&&this.compare(this.heap[s],this.heap[i])<0&&(i=s),i===e)break;this._swap(e,i),e=i;}}};var k=class{constructor(){this.head=null;this.tail=null;this._size=0;}get size(){return this._size}isEmpty(){return this._size===0}peekHead(){return this.head===null?void 0:this.head}pushTail(e){e.prev=this.tail,e.next=null,this.tail!==null?this.tail.next=e:this.head=e,this.tail=e,this._size++;}remove(e){e.prev!==null?e.prev.next=e.next:this.head=e.next,e.next!==null?e.next.prev=e.prev:this.tail=e.prev,e.prev=e.next=null,this._size--;}clear(){this.head=this.tail=null,this._size=0;}};var E=class{constructor(e,t){this.cachedIndex=-1;this.cachedUntil=0;this.size=l(e,"CombinedWindow size",1,Number.MAX_SAFE_INTEGER,true,true),this.stepMs=l(t,"CombinedWindow stepMs",1,Number.MAX_SAFE_INTEGER,true,true),this.timestamps=new Float64Array(e),this.acquired=new Int32Array(e),this.released=new Int32Array(e),this.timeouts=new Int32Array(e),this.ifSum=new Float64Array(e),this.ifCount=new Int32Array(e),this.ifMax=new Float64Array(e),this.qSum=new Float64Array(e),this.qCount=new Int32Array(e),this.qMax=new Float64Array(e),this.latSum=new Float64Array(e),this.latCount=new Int32Array(e);}bucket(e){if(e<this.cachedUntil&&e>=this.cachedUntil-this.stepMs)return this.cachedIndex;let t=Math.floor(e/this.stepMs),i=t*this.stepMs,r=t%this.size;return this.timestamps[r]!==i&&(this.timestamps[r]=i,this.acquired[r]=0,this.released[r]=0,this.timeouts[r]=0,this.ifSum[r]=0,this.ifCount[r]=0,this.ifMax[r]=0,this.qSum[r]=0,this.qCount[r]=0,this.qMax[r]=0,this.latSum[r]=0,this.latCount[r]=0),this.cachedIndex=r,this.cachedUntil=i+this.stepMs,r}addInflight(e,t){this.ifSum[e]+=t,this.ifCount[e]++,t>this.ifMax[e]&&(this.ifMax[e]=t);}addQueue(e,t){this.qSum[e]+=t,this.qCount[e]++,t>this.qMax[e]&&(this.qMax[e]=t);}recordAcquire(e,t,i){let r=this.bucket(e);this.acquired[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordAcquireQueued(e,t,i,r){let s=this.bucket(e);this.acquired[s]++,this.latSum[s]+=t,this.latCount[s]++,this.addInflight(s,i),this.addQueue(s,r);}recordRelease(e,t,i){let r=this.bucket(e);this.released[r]++,this.addInflight(r,t),this.addQueue(r,i);}recordTimeoutQueue(e,t){let i=this.bucket(e);this.timeouts[i]++,this.addQueue(i,t);}sampleBoth(e,t,i){let r=this.bucket(e);this.addInflight(r,t),this.addQueue(r,i);}addAcquired(e){this.acquired[this.bucket(e)]++;}addReleased(e){this.released[this.bucket(e)]++;}addTimeout(e){this.timeouts[this.bucket(e)]++;}addLatency(e,t){let i=this.bucket(e);this.latSum[i]+=t,this.latCount[i]++;}sampleInflight(e,t){this.addInflight(this.bucket(e),t);}sampleQueue(e,t){this.addQueue(this.bucket(e),t);}snapshot(e){let t=Math.floor(e/this.stepMs)*this.stepMs-(this.size-1)*this.stepMs,i=0,r=0,s=0,u=0,c=0,d=0,b=0,p=0,m=0,g=0,v=0;for(let h=0;h<this.size;h++)this.timestamps[h]<t||(i+=this.acquired[h],r+=this.released[h],s+=this.timeouts[h],u+=this.ifSum[h],c+=this.ifCount[h],this.ifMax[h]>d&&(d=this.ifMax[h]),b+=this.qSum[h],p+=this.qCount[h],this.qMax[h]>m&&(m=this.qMax[h]),g+=this.latSum[h],v+=this.latCount[h]);return {counts:{acquired:i,released:r,timeouts:s},inflight:{avg:c===0?0:u/c,max:d,samples:c},queue:{avg:p===0?0:b/p,max:m,samples:p},latency:{avg:v===0?0:g/v,count:v,total:g}}}reset(){this.cachedIndex=-1,this.cachedUntil=0,this.timestamps.fill(0),this.acquired.fill(0),this.released.fill(0),this.timeouts.fill(0),this.ifSum.fill(0),this.ifCount.fill(0),this.ifMax.fill(0),this.qSum.fill(0),this.qCount.fill(0),this.qMax.fill(0),this.latSum.fill(0),this.latCount.fill(0);}},F=[{size:60,stepMs:1e3},{size:60,stepMs:5e3},{size:60,stepMs:15e3},{size:60,stepMs:6e4},{size:60,stepMs:144e4}],I=class{constructor(e=F){this._totalAcquiredFast=0;this._totalAcquiredQueued=0;this._totalReleased=0;this._totalTimeouts=0;this._totalAborts=0;this._capacity=0;this._circuitOpen=false;this._circuitHalfOpen=false;if(e.length===0)throw new a("SemaphoreMetrics requires at least one WindowOptions","INVALID_ARGUMENT");this.windows=e.map(({size:r,stepMs:s})=>new E(r,s)),this.windowLabels=e.map(({size:r,stepMs:s})=>{let u=r*s;return u>=36e5&&u%36e5===0?`${u/36e5}h`:u>=6e4&&u%6e4===0?`${u/6e4}m`:u>=1e3&&u%1e3===0?`${u/1e3}s`:`${u}ms`});let t=new Set;for(let r of this.windowLabels){if(t.has(r))throw new a(`SemaphoreMetrics windows produce duplicate label "${r}" (two windows cover the same horizon)`,"INVALID_ARGUMENT");t.add(r);}let i=0;for(let r=1;r<e.length;r++)e[r].size*e[r].stepMs<e[i].size*e[i].stepMs&&(i=r);this.primaryLabel=this.windowLabels[i],this.primaryWindowMs=e[i].size*e[i].stepMs;}onAcquireFast(e,t,i){this._totalAcquiredFast++;for(let r of this.windows)r.recordAcquire(e,t,i);}onAcquireQueued(e,t,i,r){this._totalAcquiredQueued++;for(let s of this.windows)s.recordAcquireQueued(e,t,i,r);}onRelease(e,t,i){this._totalReleased++;for(let r of this.windows)r.recordRelease(e,t,i);}onTimeout(e,t){this._totalTimeouts++;for(let i of this.windows)i.recordTimeoutQueue(e,t);}onAbort(e,t){this._totalAborts++;for(let i of this.windows)i.sampleQueue(e,t);}sampleGauges(e,t,i){for(let r of this.windows)r.sampleBoth(e,t,i);}sampleQueueDepthAt(e,t){for(let i of this.windows)i.sampleQueue(e,t);}markAcquireFast(){this._totalAcquiredFast++;let e=Date.now();for(let t of this.windows)t.addAcquired(e);}markAcquireQueued(e){this._totalAcquiredQueued++;let t=Date.now();for(let i of this.windows)i.addAcquired(t),i.addLatency(t,e);}markReleased(){this._totalReleased++;let e=Date.now();for(let t of this.windows)t.addReleased(e);}markTimeout(){this._totalTimeouts++;let e=Date.now();for(let t of this.windows)t.addTimeout(e);}markAbort(){this._totalAborts++;}sampleInFlight(e){let t=Date.now();for(let i of this.windows)i.sampleInflight(t,e);}sampleQueueDepth(e){let t=Date.now();for(let i of this.windows)i.sampleQueue(t,e);}markCapacityChange(e){this._capacity=e;}markCircuitOpen(){this._circuitOpen=true,this._circuitHalfOpen=false;}markCircuitHalfOpen(){this._circuitOpen=false,this._circuitHalfOpen=true;}markCircuitClose(){this._circuitOpen=false,this._circuitHalfOpen=false;}getSnapshot(){let e=Date.now(),t={},i=0,r=0;for(let s=0;s<this.windowLabels.length;s++){let u=this.windows[s].snapshot(e);t[this.windowLabels[s]]=u,s===0&&(i=u.inflight.avg,r=u.queue.avg);}return {windows:t,meta:{inFlightLastMinute:Math.round(i),queueDepthLastMinute:Math.round(r),totalAcquiredFast:this._totalAcquiredFast,totalAcquiredQueued:this._totalAcquiredQueued,totalReleased:this._totalReleased,totalTimeouts:this._totalTimeouts,totalAborts:this._totalAborts,capacity:this._capacity,circuitOpen:this._circuitOpen,circuitHalfOpen:this._circuitHalfOpen}}}reset(){for(let e of this.windows)e.reset();this._totalAcquiredFast=0,this._totalAcquiredQueued=0,this._totalReleased=0,this._totalTimeouts=0,this._totalAborts=0,this._capacity=0,this._circuitOpen=false,this._circuitHalfOpen=false;}destroy(){this.reset();}};var _={fifo:(o,e)=>o.id-e.id,lifo:(o,e)=>e.id-o.id,fifoWithPriority:(o,e)=>o.priority-e.priority||o.id-e.id,lifoWithPriority:(o,e)=>o.priority-e.priority||e.id-o.id};function x(o){if(o.comparator!==void 0){if(typeof o.comparator!="function")throw new a("Semaphore comparator must be a function","INVALID_ARGUMENT");return o.comparator}let e=o.queueOrder??"fifoWithPriority",t=_[e];if(t===void 0)throw new a(`Semaphore queueOrder must be one of: ${Object.keys(_).join(", ")} (got ${JSON.stringify(e)})`,"INVALID_ARGUMENT");return t}function R(o){let e=x(o);return (t,i)=>{if(t.isProbe!==i.isProbe)return t.isProbe?-1:1;let r=e(t,i);return typeof r!="number"||Number.isNaN(r)?t.id-i.id:r}}var n={TASKACQUIRE:"task-acquire",TASKRELEASE:"task-release",TASKTIMEOUT:"task-timeout",TASKABORT:"task-abort",QUEUEPURGE:"queue-purge",QUEUEEVICT:"queue-evict",CIRCUITOPEN:"circuit-open",CIRCUITHALFOPEN:"circuit-half-open",CIRCUITCLOSE:"circuit-close",SHUTDOWN:"shutdown"};var M=class{constructor(e,t={}){this.pendingReleaseCount=0;this.releaseGeneration=0;this.scheduled=false;this.isShutdown=false;this.taskIdCounter=0;this.totalAcquired=0;this.totalReleased=0;this.totalTimeouts=0;this.totalEvictions=0;this.eventListeners=new Map;this.drainPromise=null;this.drainResolve=null;this.purgeIntervalId=null;this.timeoutTimerId=null;this._runSchedulerBound=()=>{this._runScheduler();};if(l(e,"Semaphore count",0,Number.MAX_SAFE_INTEGER,true,false),this.purgeIntervalMs=l(t.purgeIntervalMs??3e3,"Semaphore purgeIntervalMs",500,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxTimeout=l(t.queueMaxTimeout??1e4,"Semaphore queueMaxTimeout",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxLength=l(t.queueMaxLength??1024,"Semaphore queueMaxLength",1,Number.MAX_SAFE_INTEGER,true,true),this.queueMaxAge=l(t.queueMaxAge??3e4,"Semaphore queueMaxAge",1,Number.MAX_SAFE_INTEGER,true,true),this.rejectOnFull=t.rejectOnFull??false,this.metricsEnabled=t.metricsEnabled??true,this.debug=t.debug??false,t.circuitBreakerFailurePredicate!==void 0&&typeof t.circuitBreakerFailurePredicate!="function")throw new a("Semaphore circuitBreakerFailurePredicate must be a function","INVALID_ARGUMENT");this.failurePredicate=t.circuitBreakerFailurePredicate;let i=R({queueOrder:t.queueOrder,comparator:t.comparator});this.queue=new S(i),this.enqueueOrder=new k,this.permits=new w(e),this.circuit=t.circuitBreaker??new f({threshold:t.circuitBreakerThreshold,window:t.circuitBreakerWindow,windowBucketWidth:t.circuitBreakerWindowBucketWidth,cooldown:t.circuitBreakerCooldown,minThroughput:t.circuitBreakerMinThroughput,minFailures:t.circuitBreakerMinFailures}),this.backoff=new T({initialTimeout:t.backoffInitialTimeout,maxTimeout:t.backoffMaxTimeout,decayFactor:t.backoffDecayFactor}),this.metricsCollector=this.metricsEnabled?new I(t.metricsWindows):void 0,this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this._startPurgeInterval();}on(e,t){this.eventListeners.has(e)||this.eventListeners.set(e,new Set),this.eventListeners.get(e).add(t);}off(e,t){this.eventListeners.get(e)?.delete(t),this.eventListeners.get(e)?.size===0&&this.eventListeners.delete(e);}removeAllListeners(e){e?this.eventListeners.delete(e):this.eventListeners.clear();}hasListeners(e){let t=this.eventListeners.get(e);return t!==void 0&&t.size>0}emit(e,...t){let i=this.eventListeners.get(e);if(!(!i||i.size===0)){if(i.size===1){let r=i.values().next().value;try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}return}for(let r of Array.from(i))try{r(...t);}catch(s){console.warn(`[Semaphore] Error in listener for "${e}":`,s);}}}_tryAcquireFast(e){return this.circuit.isHalfOpen?this.circuit.hasProbeInFlight||!this.permits.hasCapacityFor(e)?null:(this.circuit.markProbeInFlight(),this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,probe:true}),this._createRelease(true,e)):this.queue.size>0||!this.permits.hasCapacityFor(e)?null:(this.permits.acquire(e),this.totalAcquired++,this.metricsCollector?.onAcquireFast(Date.now(),this.permits.inFlight,this.queue.size),this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._createRelease(false,e))}_createRelease(e=false,t=1){this.pendingReleaseCount++;let i=this.releaseGeneration,r=false;return ()=>{if(r||i!==this.releaseGeneration){this.debug&&console.warn("[Semaphore] release() called after already released (no-op)");return}r=true,this.pendingReleaseCount--,this.permits.release(t),this.totalReleased++,this.metricsCollector?.onRelease(Date.now(),this.permits.inFlight,this.queue.size),e&&this.circuit.isHalfOpen&&(this.circuit.handleProbeSuccess(),this.emit(n.CIRCUITCLOSE),this.metricsCollector?.markCircuitClose(),this.debug&&console.info("[Semaphore] Circuit closed after successful probe")),this.permits.assertInvariant(this.debug),this.hasListeners(n.TASKRELEASE)&&this.emit(n.TASKRELEASE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available}),this._checkDrain(),this.schedule();}}_checkDrain(){this.drainResolve&&this.queue.size===0&&this.permits.available===this.permits.capacity&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null);}_enqueue(e){this.queue.insert(e),this.enqueueOrder.pushTail(e),this._armTimeout();}_dequeue(e){this.queue.delete(e)!==void 0&&(this.enqueueOrder.remove(e),this.enqueueOrder.size===0&&this._clearTimeout());}_armTimeout(){if(this.timeoutTimerId!==null)return;let e=this.enqueueOrder.peekHead();if(e===void 0)return;let t=Math.max(0,e.enqueueTime+this.queueMaxTimeout-Date.now());this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),t);}_clearTimeout(){this.timeoutTimerId!==null&&(clearTimeout(this.timeoutTimerId),this.timeoutTimerId=null);}_fireTimeout(){if(this.timeoutTimerId=null,this.isShutdown)return;let e=Date.now(),t=0,i=this.enqueueOrder.peekHead();for(;i!==void 0&&i.enqueueTime+this.queueMaxTimeout<=e;){let r=i.claim();this._dequeue(i),r&&(this._timeoutTask(i),t++),i=this.enqueueOrder.peekHead();}if(i!==void 0){let r=Math.max(0,i.enqueueTime+this.queueMaxTimeout-e);this.timeoutTimerId=setTimeout(()=>this._fireTimeout(),r);}t>0&&(this._checkDrain(),this.schedule());}_evictQueueOnCircuitOpen(e){if(this.queue.size===0)return;let t=0;for(let i of this.queue.toArray()){if(i===e||i.isProbe)continue;let r=i.discard(new a("Circuit breaker opened while task was queued","CIRCUIT_OPEN"));this._dequeue(i),r&&(t++,this.totalEvictions++,this.emit(n.QUEUEEVICT,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Evicted queued task #${i.id}: circuit opened`));}t>0&&this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size);}_timeoutTask(e){if(this.totalTimeouts++,this.circuit.recordFailure(),this.backoff.onTimeout(),e.isProbe)this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe timed out");else {let t=this.circuit.evaluateAndTrip();t.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:t.timeoutRate,recentTimeouts:t.failures,total:t.attempts}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened. Rate: ${(t.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen(e));}this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.TASKTIMEOUT,{queueLength:this.queue.size,backoffDelay:this.backoff.currentDelay,taskId:e.id}),this.debug&&console.warn(`[Semaphore] Task #${e.id} timed out after ${this.queueMaxTimeout}ms`),e.reject(new a(`Semaphore acquire timed out after ${this.queueMaxTimeout}ms (queue: ${this.queue.size})`,"TIMEOUT"));}_onTaskAbort(e,t){this._dequeue(e),e.isProbe&&this.circuit.releaseProbeSlot(),this.metricsCollector?.onAbort(Date.now(),this.queue.size),this.emit(n.TASKABORT),this.debug&&console.info(`[Semaphore] Task #${e.id} aborted`),t(new a("Semaphore acquire aborted","ABORTED")),this._checkDrain(),this.schedule();}schedule(){if(this.scheduled||this.isShutdown)return;this.scheduled=true;let e=this.backoff.currentDelay;e>0?setTimeout(this._runSchedulerBound,e).unref?.():queueMicrotask(this._runSchedulerBound);}_runScheduler(){if(!this.isShutdown){this.scheduled=false;try{for(;this.queue.size>0&&!this.circuit.isOpen;){let e=this.queue.peek();if(!e||this.circuit.isHalfOpen&&e.id!==this.circuit.probeTaskId||!this.permits.hasCapacityFor(e.weight))break;let t=this.queue.pop();this.enqueueOrder.remove(t),this.enqueueOrder.size===0&&this._clearTimeout();let i=Date.now(),r=Math.max(0,i-t.enqueueTime);this.permits.acquire(t.weight),this.totalAcquired++,this.metricsCollector?.onAcquireQueued(i,r,this.permits.inFlight,this.queue.size),this.permits.assertInvariant(this.debug),t.dispatch(()=>this._createRelease(t.isProbe,t.weight))&&this.hasListeners(n.TASKACQUIRE)&&this.emit(n.TASKACQUIRE,{queued:this.queue.size,running:this.permits.capacity-this.permits.available,...t.isProbe?{probe:!0}:{}});}this._checkDrain();}catch(e){e instanceof Error?console.error("[Semaphore] Scheduler error:",e.message,e.stack):console.error("[Semaphore] Scheduler error:",e);}}}_startPurgeInterval(){this.purgeIntervalId!==null&&clearInterval(this.purgeIntervalId),this.purgeIntervalId=setInterval(()=>{this.isShutdown||this._purgeStaleTasks();},this.purgeIntervalMs),this.purgeIntervalId.unref?.();}_purgeStaleTasks(){let e=Date.now(),t=this.queue.size,i=this.enqueueOrder.peekHead();for(;i!==void 0&&e-i.enqueueTime>this.queueMaxAge;){this.circuit.probeTaskId===i.id&&this.circuit.releaseProbeSlot();let r=i.discard(new a(`Task purged after ${this.queueMaxAge}ms`,"PURGED"));this._dequeue(i),r&&(this.totalTimeouts++,this.metricsCollector?.onTimeout(Date.now(),this.queue.size),this.emit(n.QUEUEPURGE,{id:i.id,priority:i.priority,enqueueTime:i.enqueueTime,weight:i.weight}),this.debug&&console.warn(`[Semaphore] Purged stale task #${i.id}`)),i=this.enqueueOrder.peekHead();}this.debug&&this.queue.size<t&&console.info(`[Semaphore] Purged ${t-this.queue.size} stale tasks`),this.queue.size<t&&(this._checkDrain(),this.schedule());}tryAcquire(e=1){return this.isShutdown||!Number.isInteger(e)||e<1||e>this.permits.capacity||(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)?null:this._tryAcquireFast(e)}acquire(e,t=0,i=1){if(this.isShutdown)return Promise.reject(new a("Semaphore is shut down","SHUTDOWN"));if(!Number.isInteger(i)||i<1||i>this.permits.capacity)return Promise.reject(new a(`Invalid weight: ${i} (must be integer in 1..${this.permits.capacity})`,"INVALID_WEIGHT"));if(typeof t!="number"||!Number.isFinite(t))return Promise.reject(new a(`Invalid priority: ${t} (must be a finite number)`,"INVALID_PRIORITY"));if(this.circuit.checkAndTransition()&&(this.emit(n.CIRCUITHALFOPEN),this.metricsCollector?.markCircuitHalfOpen(),this.debug&&console.info("[Semaphore] Circuit entering half-open"),this.schedule()),this.circuit.isOpen)return Promise.reject(new a(`Circuit breaker open, retry in ${this.circuit.cooldownRemaining}ms`,"CIRCUIT_OPEN"));if(this.circuit.isHalfOpen&&this.circuit.hasProbeInFlight)return Promise.reject(new a("Circuit breaker half-open, probe in flight","CIRCUIT_HALF_OPEN"));if(e?.aborted)return Promise.reject(new a("Semaphore acquire aborted before start","ABORTED"));this.circuit.trackAttempt();let r=this._tryAcquireFast(i);if(r)return Promise.resolve(r);let s=this.circuit.isHalfOpen&&!this.circuit.hasProbeInFlight;return !s&&this.rejectOnFull?Promise.reject(new a("Semaphore at capacity (rejectOnFull)","QUEUE_FULL")):!s&&this.queue.size>=this.queueMaxLength?Promise.reject(new a(`Queue full (${this.queueMaxLength})`,"QUEUE_FULL")):new Promise((u,c)=>{let d=++this.taskIdCounter,b=Date.now(),p=s,m=new y({id:d,priority:p?Number.MIN_SAFE_INTEGER:t,enqueueTime:b,isProbe:p,resolve:u,reject:c,abortSignal:e,weight:i});m.arm(()=>this._onTaskAbort(m,c)),p&&this.circuit.claimProbeSlot(d),this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size+1),this._enqueue(m),this.schedule();})}peekQueue(){let e=[],t=this.enqueueOrder.peekHead();for(;t!==void 0;)e.push({id:t.id,priority:t.priority,enqueueTime:t.enqueueTime,weight:t.weight,isProbe:t.isProbe}),t=t.next??void 0;return e}async use(e,t,i=0,r=1){let s=await this.acquire(t,i,r),u=this.failurePredicate!==void 0&&this.circuit.isHalfOpen;try{let c=await e();return s(),c}catch(c){if(this.failurePredicate!==void 0){let d=false;try{d=this.failurePredicate(c)===!0;}catch(b){console.warn("[Semaphore] circuitBreakerFailurePredicate threw (rejection treated as non-matching):",b);}d&&(u&&this.circuit.isHalfOpen?(this.circuit.recordFailure(),this.circuit.handleProbeFailure(),this.emit(n.CIRCUITOPEN,{timeoutRate:1,recentTimeouts:1,total:1,reason:"half-open-probe-failed"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn("[Semaphore] Circuit re-opened: half-open probe operation failed")):this.reportFailure());}throw s(),c}}drain(e){return this.isShutdown?Promise.reject(new a("Cannot drain: semaphore is shut down","SHUTDOWN")):(e!==void 0&&l(e,"drain timeoutMs",1,Number.MAX_SAFE_INTEGER,true,true),this.drainPromise?this.drainPromise:this.queue.size===0&&this.permits.available===this.permits.capacity?Promise.resolve():(this.drainPromise=new Promise((t,i)=>{if(this.drainResolve=t,e!==void 0){let r=setTimeout(()=>{this.drainResolve=null,this.drainPromise=null,i(new a(`drain() timed out after ${e}ms`,"TIMEOUT"));},e),s=this.drainResolve;this.drainResolve=()=>{clearTimeout(r),s();};}}),this.drainPromise))}reset(e={}){if(this.isShutdown)throw new a("Cannot reset a semaphore that has been shut down","SHUTDOWN");for(let t of this.queue.toArray())t.discard(new a("Semaphore reset","SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this._clearTimeout(),this.metricsCollector?.reset(),this.permits.reset(),this.backoff.reset(),this.circuit.reset(),this.releaseGeneration++,this.pendingReleaseCount=0,this.scheduled=false,this.isShutdown=false,this.taskIdCounter=0,this.totalAcquired=0,this.totalReleased=0,this.totalTimeouts=0,this.totalEvictions=0,e.clearListeners&&this.eventListeners.clear(),this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this._startPurgeInterval(),this.metricsCollector?.markCapacityChange(this.permits.capacity),this.metricsCollector?.sampleGauges(Date.now(),this.permits.inFlight,this.queue.size),this.debug&&console.info("[Semaphore] Reset to initial state");}shutdown(e="Semaphore shutdown"){if(!this.isShutdown){this.isShutdown=true,this.debug&&console.info(`[Semaphore] Shutdown: ${e}`),this.purgeIntervalId!==null&&(clearInterval(this.purgeIntervalId),this.purgeIntervalId=null),this._clearTimeout();for(let t of this.queue.toArray())t.discard(new a(e,"SHUTDOWN"));this.queue.clear(),this.enqueueOrder.clear(),this.metricsCollector?.destroy(),this.metricsCollector=void 0,this.drainResolve&&(this.drainResolve(),this.drainResolve=null,this.drainPromise=null),this.emit(n.SHUTDOWN,e);}}cancel(){if(this.isShutdown)return;let e=this.queue.toArray();for(let t of e)t.isProbe&&this.circuit.releaseProbeSlot(),t.discard(new a("Semaphore acquire cancelled","CANCELLED")),this._dequeue(t);this.metricsCollector?.sampleQueueDepthAt(Date.now(),this.queue.size),this.debug&&console.info(`[Semaphore] Cancelled ${e.length} queued tasks`),this._checkDrain(),this.schedule();}reportFailure(){if(this.isShutdown)return;this.circuit.recordFailure();let e=this.circuit.evaluateAndTrip();e.tripped&&(this.emit(n.CIRCUITOPEN,{timeoutRate:e.timeoutRate,recentTimeouts:e.failures,total:e.attempts,reason:"reported-failure"}),this.metricsCollector?.markCircuitOpen(),this.debug&&console.warn(`[Semaphore] Circuit opened via reportFailure(). Rate: ${(e.timeoutRate*100).toFixed(1)}%`),this._evictQueueOnCircuitOpen());}status(){let e=this.metricsCollector?.getSnapshot()??null,t=this.metricsCollector!==void 0?e?.windows?.[this.metricsCollector.primaryLabel]?.counts:void 0,i=(this.metricsCollector?.primaryWindowMs??6e4)/1e3,r=t?.acquired??0,s=t?.timeouts??0,u=this.enqueueOrder.peekHead(),c=u===void 0?0:Math.max(0,Date.now()-u.enqueueTime);return {status:{running:this.permits.capacity-this.permits.available,queued:this.queue.size,available:this.permits.available,inFlight:this.permits.inFlight,pendingReleases:this.pendingReleaseCount,circuitOpen:this.circuit.isOpen,circuitHalfOpen:this.circuit.isHalfOpen,backoffDelay:Math.round(this.backoff.currentDelay),requestsPerSecond:+(r/i).toFixed(2),timeoutRate1m:r+s>0?+(s/(r+s)*100).toFixed(1):0,queueAge:c},lifetime:{totalAcquired:this.totalAcquired,totalReleased:this.totalReleased,totalTimeouts:this.totalTimeouts,totalEvictions:this.totalEvictions,circuitBreakerCooldownRemaining:this.circuit.cooldownRemaining},metrics:e}}get availablePermits(){return this.permits.available}isAvailable(){return !this.isShutdown&&!this.circuit.isOpen&&!this.permits.isFull}get capacity(){return this.permits.capacity}get circuitState(){return this.circuit.state}get queueLength(){return this.queue.size}};var O={tripped:false},C=class{constructor(){this.state="closed";this.isOpen=false;this.isHalfOpen=false;this.hasProbeInFlight=false;this.probeTaskId=null;this.cooldownRemaining=0;}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return O}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){}};var P={tripped:false},q=class{constructor(){this.state="closed";this.hasProbeInFlight=false;this.probeTaskId=null;}get isOpen(){return this.state==="open"}get isHalfOpen(){return false}get cooldownRemaining(){return 0}open(){this.state="open";}close(){this.state="closed";}checkAndTransition(){return false}trackAttempt(){}recordFailure(){}evaluateAndTrip(){return P}markProbeInFlight(){}claimProbeSlot(){}releaseProbeSlot(){}handleProbeSuccess(){}handleProbeFailure(){}reset(){this.state="closed";}};export{q as ManualCircuitBreaker,C as NoopCircuitBreaker,_ as QUEUE_ORDERINGS,f as SaturationCircuitBreaker,M as Semaphore,a as SemaphoreError,n as SemaphoreEvents};//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map
{
"name": "regulo",
"version": "1.3.1",
"version": "1.3.4",
"description": "Control the heat — a priority-queue semaphore with weighted permits, a saturation circuit breaker, adaptive backoff, and built-in metrics. Zero dependencies.",

@@ -5,0 +5,0 @@ "license": "MIT",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display