@stackone/transport 2.17.0 → 2.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,4 +1,4 @@
1
- var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__commonJSMin=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`redis`);s=__toESM(s);let c=require(`@stackone/expressions`),l=require(`axios`);l=__toESM(l);let u=require(`node:https`);u=__toESM(u);let d=require(`crypto`),f=require(`node:timers`),p=require(`jsonpath-plus`),m=require(`@stackone/redaction`),h=require(`qs`);h=__toESM(h);const createAuthorizationHeaders=e=>{switch(e.type){case`none`:return{};case`basic`:return createBasicAuthorizationHeader(e);case`bearer`:return createBearerAuthorizationHeader(e);case`oauth2`:return createBearerAuthorizationHeader(e);default:throw Error(`Invalid authentication type`)}},createBasicAuthorizationHeader=({username:e=``,password:t=``,encoding:n=`base64`})=>{let r=n;return{authorization:`Basic ${Buffer.from(`${e}:${t}`).toString(r)}`}},createBearerAuthorizationHeader=({token:e,includeBearer:t})=>({authorization:`${t?`Bearer `:``}${e}`});var LockManager=class{constructor(){this.locks=new Map}async withLock(e,t){await this.lock(e);try{return t()}finally{this.unlock(e)}}async lock(e){let t,n=new Promise(e=>t=e),r=this.locks.has(e),i=this.locks.get(e);r&&i?(i.push({lock:n,unlock:t}),await i[i.length-2].lock):this.locks.set(e,[{lock:n,unlock:t}])}unlock(e){let t=this.locks.has(e),n=this.locks.get(e);if(t&&n&&n.length>0){let e=n.shift()?.unlock;e?.()}this.queueLength(e)===0&&this.locks.delete(e)}queueLength(e){return this.locks.get(e)?.length}close(){this.locks.clear()}};const g=1e3,_=100,v=60,y=6e4,b=60,x=y,S=y*10,ee=100,C=10;let w=function(e){return e.MemoryStorePruneError=`MemoryStorePruneError`,e}({});var MemoryStore=class{constructor(e={}){this.lastAccessedAt=Date.now(),this.config=e,this.initialize(e)}initialize(e=this.config){this.instantiator=e?.instantiator??`Unknown`,this.logger=e?.logger,this.dataStore=e?.dataStore??new Map,this.lockManager=e?.lockManager??new LockManager,this.expiryMap=e?.expiryMap??new Map,this.evictionFrequency=e?.evictionFrequency??6e4,this.staleDataThreshold=e?.staleDataThreshold??6e5,this.truncateThreshold=e?.truncateThreshold??100,this.truncationPercentage=e?.truncationPercentage??10,this.typeGuard=e?.typeGuard,this.dispose=e?.dispose,this.startEvictionTask()}async getData(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>this.dataStore.get(e)??null)}async setData({key:e,value:t,cacheTTL:n=60}){if(this.isReady()||this.initialize(),this.updateLastAccessedAt(),(0,o.notMissing)(this.typeGuard)&&!this.typeGuard(t))return!1;let r=n*1e3,i=Date.now()+r;return await this.lockManager.withLock(e,async()=>{((0,o.notMissing)(this.typeGuard)&&this.typeGuard(t)||(0,o.isMissing)(this.typeGuard)&&this.typeGuardBypass(t))&&this.dataStore.set(e,t),this.expiryMap.set(e,i)}),!0}typeGuardBypass(e){return this.logger?.debug({category:`MemoryStore`,message:`${this.instantiator} MemoryStore setting data without type guard - you should probably configure one`}),!0}async delete(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>{if(this.dispose){let t=this.dataStore.get(e);await this.dispose(e,t)}return this.dataStore.delete(e)})}async pruneExpiredKeys(){let e=this.dataStore.size,t=e>=this.truncateThreshold;if(e<=0)return;let n=[],r=0;return this.dataStore.forEach(async(e,i)=>{let a=Date.now(),o=this.expiryMap.get(i)??0,s=this.truncateThreshold*this.truncationPercentage/100;(o<=a||t&&r>=0&&r<=s)&&n.push(this.lockManager.withLock(i,async()=>(this.dispose&&await this.dispose(i,e),this.dataStore.delete(i)))),r++}),await Promise.all(n),{dataStoreSize:e,prunedDataStoreSize:this.dataStore.size}}startEvictionTask(){if((0,o.notMissing)(this.evictionInterval))return;let executePrune=async()=>{let e;try{if(this.lastAccessedAt+this.staleDataThreshold<Date.now()){this.logger?.warning({message:`Closing the ${this.instantiator}'s MemoryStore instance - received no requests for a while.`,category:`MemoryStore`}),this.close();return}e=await this.pruneExpiredKeys(),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}catch(e){e instanceof Error&&this.logger?.error({message:`Error during pruning expired keys:`,category:`MemoryStore`,error:e,code:w.MemoryStorePruneError}),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}finally{if((0,o.notMissing)(e?.dataStoreSize)&&(0,o.notMissing)(e?.prunedDataStoreSize)){let{dataStoreSize:t,prunedDataStoreSize:n}=e,r=t-n;this.logger?.debug({message:`Pruned ${r} expired keys, ${n} remain, scheduling next prune.`,category:`MemoryStore`,context:{instantiator:this.instantiator}})}}};this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}stopEvictionTask(){this.evictionInterval&&=(clearTimeout(this.evictionInterval),void 0)}updateLastAccessedAt(){this.lastAccessedAt=Date.now()}isReady(){return(0,o.notMissing)(this.evictionInterval)&&(0,o.notMissing)(this.dataStore)&&(0,o.notMissing)(this.expiryMap)&&(0,o.notMissing)(this.lockManager)}close(){this.stopEvictionTask(),this.dataStore.clear(),this.expiryMap.clear(),this.lockManager.close()}async listData({partialKey:e,cursor:t,limit:n}){let r=Array.from(this.dataStore.keys()).filter(t=>t.includes(e)),i=[],a=t?parseInt(t,10):0;for(let e=a;e<n+a;e++){let t=r[e];if(!t)break;let a=await this.getData(t);if(a&&i.push(a),i.length>=n)break}return{items:i,cursor:i.length<n?void 0:(a+n).toString()}}};const T=1e3,E=6e4;let D=function(e){return e.EventClientResolveError=`EventClientResolveError`,e}({});var EventClient=class{constructor(e,t,n){this.executorMethodStore=null,this.promiseStore=null,this.eventClientConfig=null,this.executorMethodStoreConfig=null,this.pendingPromiseStoreConfig=null,this.eventClientConfig=e,this.executorMethodStoreConfig=t,this.pendingPromiseStoreConfig=n;let r=e?.instantiator?`${e?.instantiator}(${this.constructor.name})`:this.constructor.name,i={logger:this.logger,dispose:this.defaultExecutorMethodDispose,typeGuard:this.defaultExecutorMethodTypeGuard,...this.executorMethodStoreConfig??{},instantiator:r},a={logger:this.logger,dispose:this.defaultPendingPromiseDispose,typeGuard:this.defaultPendingPromiseTypeGuard,...this.pendingPromiseStoreConfig??{},instantiator:r};this.executorMethodStore=new MemoryStore(i),this.promiseStore=new MemoryStore(a)}async setPendingEvent(e,t){let n={resolve:void 0,reject:void 0},r=new Promise((e,t)=>{n.resolve=e,n.reject=t}),i=t/1e3;await this.executorMethodStore?.setData({key:e,value:n,cacheTTL:i}),await this.promiseStore?.setData({key:e,value:r,cacheTTL:i})}async waitForEvent(e,t){let n=await this.promiseStore?.getData(e);return(0,o.notMissing)(n)?n:(await this.setPendingEvent(e,t),this.getPendingEvent(e))}async getPendingEvent(e){return this.promiseStore?.getData(e)??null}async deleteEvent(e){return(await Promise.all([this.promiseStore?.delete(e),this.executorMethodStore?.delete(e)])).every(Boolean)}async resolveEvent(e,t){try{let n=await this.executorMethodStore?.getData(e);(0,o.isMissing)(n)&&(await this.setPendingEvent(e,this.eventClientConfig?.defaultTimeoutMS??6e4),n=await this.executorMethodStore?.getData(e)),n?.resolve?.(t)}catch(t){t instanceof Error&&this.logger.error({message:`Error handling event for key ${e}: ${t.message}`,category:this.constructor.name,context:{eventKey:e},error:t,code:D.EventClientResolveError})}}async defaultExecutorMethodDispose(e,t){(0,o.notMissing)(t?.resolve)?t.resolve(this.eventClientConfig?.timeoutResolveValue):(0,o.notMissing)(t?.reject)&&t.reject(Error(`Event key: ${e} was not resolved or the event was disposed`))}defaultExecutorMethodTypeGuard(e){return(0,o.isObject)(e)&&e.hasOwnProperty(`resolve`)&&e.hasOwnProperty(`reject`)}async defaultPendingPromiseDispose(e,t){t instanceof Promise&&t?.finally(()=>{})}defaultPendingPromiseTypeGuard(e){return e instanceof Promise}},AsyncSingleton=class{constructor(){this.instance=null,this.initPromise=null,this.retryTimeout=null,this.status=`uninitialized`,this.initOptions=null,this.initArgs=[]}getRetryDelay(){return 5e3}getSingleton(e){throw Error(`getSingleton method not implemented`)}async getInstance(e,...t){return this.instance?this.instance:((0,o.isMissing)(this.initPromise)&&(this.initOptions=e??null,this.initArgs=t,this.initPromise=this.init(e??null,...t)),this.initPromise)}getInstanceIfReady(){return this.instance}isReady(){return this.status===`ready`}hasInitFailed(){return this.status===`failed`}async init(e,...t){try{let n=await this.initInstance(e,...t);return this.instance=n,this.status=`ready`,n}catch(e){throw this.status=`failed`,this.initPromise=null,(0,o.isMissing)(this.retryTimeout)&&(this.retryTimeout=setTimeout(()=>{this.retryTimeout=null,this.getInstance(this.initOptions,...this.initArgs).catch(()=>{})},this.getRetryDelay())),e}}reset(){this.instance=null,this.initPromise=null,this.initOptions=null,this.status=`uninitialized`,this.retryTimeout&&clearTimeout(this.retryTimeout),this.retryTimeout=null}};let O=function(e){return e.RedisClientError=`RedisClientError`,e.RedisClientCommandError=`RedisClientCommandError`,e.RedisClientDeleteError=`RedisClientDeleteError`,e.RedisClientInvalidTTL=`RedisClientInvalidTTL`,e.RedisClientListError=`RedisClientListError`,e.RedisClientNotInitialized=`RedisClientNotInitialized`,e.RedisClientPublishError=`RedisClientPublishError`,e.RedisClientReadError=`RedisClientReadError`,e.RedisClientRedisNotReady=`RedisClientRedisNotReady`,e.RedisClientScriptError=`RedisClientScriptError`,e.RedisClientScriptExecuteError=`RedisClientScriptExecuteError`,e.RedisClientScriptLoadError=`RedisClientScriptLoadError`,e.RedisClientSubscribeError=`RedisClientSubscribeError`,e.RedisClientUnsubscribeError=`RedisClientUnsubscribeError`,e.RedisClientWriteError=`RedisClientWriteError`,e}({});const buildRedisClientInstance=async(e,t,n)=>{try{return await te.build(e,t,n)??void 0}catch(e){let r=e;t?.error({message:`Error building Cache Manager`,error:r,code:O.RedisClientError,category:n??`buildRedisClientInstance`});return}};var te=class RedisClient{#e;#t;static async build({getRedisClient:e=s.createClient,host:t,port:n,tls:r,reconnect:i=!0,database:a},o,c){let l=new RedisClient;l.#t=o;try{l.#e=e({socket:{reconnectStrategy:i?e=>Math.min(e*20,5e3):!1,host:t,port:n,tls:r},database:a,disableOfflineQueue:!0});let o=getDefaultRedisListeners(c??`RedisClient`,l.#t);return addRedisEventHandlers(l.#e,o),await l.#e.connect(),l}catch(e){let t=e;return l.#t?.error({message:`Error building Cache Manager.`,error:t,code:O.RedisClientError,category:c??`RedisClient`}),null}}#n(e){try{return JSON.parse(e)}catch{return e}}async getData(e){if(!this.#i())return null;try{let t=await this.#e.get(e);if(!t)return null;let n=this.#n(t);return(0,o.isString)(n)?t:n}catch(e){let t=e;return this.#t?.error({message:`Error getting data`,error:t,code:O.RedisClientReadError,category:RedisClient.name}),null}}async setData({key:e,value:t,cacheTTL:n,groupKey:r}){if(!this.#i())return!1;try{let i=(0,o.isString)(t)?t:JSON.stringify(t);return await this.#e.set(e,i,{EX:n}),(0,o.notMissing)(r)&&await this.#e.sAdd(r,[e]),!0}catch(e){let t=e;return this.#t?.error({message:`Error setting data`,error:t,code:O.RedisClientWriteError,category:RedisClient.name}),!1}}async executeScript({sha1:e,keys:t,args:n}){if(!this.#i())return null;try{return await this.#e.evalSha(e,{keys:t,arguments:n})}catch(e){let t=e;throw this.#t?.error({message:`Error executing script`,error:t,code:O.RedisClientScriptExecuteError,category:RedisClient.name}),t}}async loadScript(e){if(!this.#i())return null;try{return await this.#e.scriptLoad(e)}catch(e){let t=e;return this.#t?.error({message:`Error loading script`,error:t,code:O.RedisClientScriptLoadError,category:RedisClient.name}),null}}async scriptExists(e){if(!this.#i())return e.map(()=>!1);try{return(await this.#e.scriptExists(e)).map(e=>!!e)}catch(t){let n=t;return this.#t?.error({message:`Error checking script existence`,error:n,code:O.RedisClientScriptError,category:RedisClient.name}),e.map(()=>!1)}}async#r(e,t,n){if(!this.#i())return null;if(!Number.isFinite(n)||n<=0)return this.#t?.error({message:`Invalid cacheTTL parameter`,category:RedisClient.name,code:O.RedisClientInvalidTTL}),null;try{let r=[{args:[e,t]},{args:[`expire`,t,n.toString()]}],i=(await this.#e.multiExecutor(r))?.[0];return typeof i==`number`?i:null}catch(t){let n=t;return this.#t?.error({message:`Error executing ${e} operation`,error:n,code:O.RedisClientCommandError,category:RedisClient.name}),null}}async increment(e,t){return this.#r(`incr`,e,t)}async decrement(e,t){return this.#r(`decr`,e,t)}async subscribe(e,t){if(!this.#i())return!1;try{return await this.#e.pSubscribe(e,t),!0}catch(t){let n=t;return this.#t?.error({message:`Error subscribing to ${e}`,error:n,code:O.RedisClientSubscribeError,category:RedisClient.name}),!1}}async unsubscribe(e){if(!this.#i())return!1;try{return await this.#e.pUnsubscribe(e),!0}catch(t){let n=t;return this.#t?.error({message:`Error unsubscribing from ${e}`,error:n,code:O.RedisClientUnsubscribeError,category:RedisClient.name}),!1}}async publish(e,t){if(!this.#i())return null;try{let n=await this.#e.publish(e,t);return n===0&&this.#t?.debug({message:`No subscribers found for channel ${e}`,category:RedisClient.name}),n}catch(t){let n=t;return this.#t?.error({message:`Error publishing to ${e}`,error:n,code:O.RedisClientPublishError,category:RedisClient.name}),null}}getClient(){return this.#i()?this.#e:null}#i(){let e=this.#e.isReady&&this.#e.isOpen;return e||this.#t?.error({message:`Redis Client is not ready.`,category:RedisClient.name,code:O.RedisClientRedisNotReady}),e}async listData({partialKey:e,limit:t,cursor:n}){try{let r=n?parseInt(n,10):0,i=await this.#e.sScan(e,r,{COUNT:t}),a=[];for(let e of i.members){let t=await this.getData(e);(0,o.notMissing)(t)&&a.push(t)}return{items:a,cursor:i.cursor>0?i.cursor.toString():void 0}}catch(e){let t=e;return this.#t?.error({message:`Error listing data`,error:t,code:O.RedisClientListError,category:RedisClient.name}),{items:null}}}async deleteData(e){try{if(!this.#i())return!1;let t=await this.#e.del(e);return t===0&&this.#t?.debug({message:`No keys deleted for ${e}`,category:RedisClient.name}),t>0}catch(e){let t=e;return this.#t?.error({message:`Error deleting data`,error:t,code:O.RedisClientDeleteError,category:RedisClient.name}),!1}}};const addRedisEventHandlers=(e,t)=>{t.forEach(({eventName:t,listener:n})=>{e.on(t,n)})},getDefaultRedisListeners=(e=`RedisClient`,t)=>[{eventName:`error`,listener:n=>{t?.error({message:`Redis client error ${n.message}`,error:n,code:O.RedisClientError,category:e})}},{eventName:`ready`,listener:()=>{t?.info({message:`Redis client ready`,category:e})}},{eventName:`connect`,listener:()=>{t?.info({message:`Redis client connected`,category:e})}},{eventName:`reconnecting`,listener:()=>{t?.info({message:`Redis client reconnecting`,category:e})}},{eventName:`end`,listener:()=>{t?.info({message:`Redis client disconnected`,category:e})}}];let ne=function(e){return e.ScriptManagerExecutionError=`ScriptManagerExecutionError`,e.ScriptManagerLoadingError=`ScriptManagerLoadingError`,e}({});const re=1500;var ScriptManager=class extends AsyncSingleton{constructor(...e){super(...e),this.isInitialConnection=!0,this.reloadInProgress=null,this.lastReloadTime=0}async initInstance({redisClientConfig:e=this.redisClientConfig,cacheClient:t=this.cacheClient,scripts:n=this.scripts,scriptMap:r=this.scriptMap,logger:i=this.logger,additionalArgs:a=this.additionalArgs}){let s=t??await buildRedisClientInstance(e,i,this.name);if((0,o.isMissing)(s))throw Error(`Failed to build Redis client`);return this.redisClientConfig=e,this.logger=i,this.cacheClient=s,this.scripts=n,this.scriptMap=r??new Map,this.additionalArgs=a??[],await this.loadScripts(n,r),this.setupReconnectHandler(),await this.additionalInitialization(...a??[]),this}setupReconnectHandler(){let e=this.cacheClient?.getClient?.();(0,o.notMissing)(e)&&(e.on(`ready`,async()=>{this.isInitialConnection?this.isInitialConnection=!1:(this.logger?.info({message:`Redis reconnected - reloading scripts`,category:this.name}),await this.reloadScripts())}),e.on(`end`,()=>{this.logger?.info({message:`Redis connection closed`,category:this.name})}))}async reloadScripts(){if((0,o.notMissing)(this.reloadInProgress))return this.logger?.info({message:`Script reload already in progress, waiting for completion`,category:this.name}),this.reloadInProgress;if(!((0,o.isMissing)(this.scripts)||Object.keys(this.scripts).length===0)){this.reloadInProgress=this.performReload();try{await this.reloadInProgress}finally{this.reloadInProgress=null}}}async performReload(){this.logger?.info({message:`Reloading ${Object.keys(this.scripts).length} scripts after Redis reconnection`,category:this.name}),this.scriptMap.clear(),await this.loadScripts(this.scripts),this.lastReloadTime=Date.now()}async loadScripts(e,t){if((0,o.notMissing)(t))for(let[e,n]of t)this.scriptMap.set(e,n);let n=Object.entries(e),r=n.map(([e])=>this.scriptMap.get(e)).filter(o.notMissing),i=new Map;if(r.length>0&&(0,o.notMissing)(this.cacheClient?.scriptExists)){let e=await this.cacheClient.scriptExists(r);if((0,o.notMissing)(e)){r.forEach((t,n)=>{i.set(t,e[n]??!1)});let t=e.filter(Boolean).length;t>0&&this.logger?.info({message:`${t}/${r.length} scripts already exist in Redis; skipping load for existing scripts`,category:this.name})}}for(let[e,t]of n){let n=this.scriptMap.get(e);if(n&&i.get(n))continue;let r=await this.cacheClient?.loadScript?.(t);(0,o.notMissing)(r)?this.scriptMap?.set(e,r):this.logger?.error({message:`Error loading script ${e}`,category:this.name,code:ne.ScriptManagerLoadingError})}}async executeScript(e,t,n){if(!this.isRedisReady())return this.logger?.warning({message:`Redis not ready, cannot execute script ${e}`,category:this.name,context:{keys:t,args:n}}),null;let r=this.scriptMap?.get(e);if((0,o.isMissing)(r))throw this.logger?.error({message:`Script for ${e} not found in script map`,category:this.name,code:ne.ScriptManagerExecutionError}),Error(`Script for ${e} not found`);try{return await this.cacheClient?.executeScript?.({sha1:r,keys:t,args:n})??null}catch(i){if(i instanceof Error&&i.message.includes(`NOSCRIPT`)){let i=Date.now()-this.lastReloadTime;if(i<re){let t=re-i;this.logger?.info({message:`Script ${e} not found, reload occurred ${i}ms ago. Waiting ${t}ms before reloading`,category:this.name}),await(0,o.delay)(t)}if(this.logger?.info({message:`Script ${e} not found in Redis, reloading scripts`,category:this.name}),await this.reloadScripts(),r=this.scriptMap?.get(e),(0,o.isMissing)(r))throw Error(`Script for ${e} could not be reloaded`);return await this.cacheClient?.executeScript?.({sha1:r,keys:t,args:n})??null}throw i instanceof Error&&this.logger?.error({message:`Error executing script ${e}: ${i.message}`,category:this.name,context:{keys:t,args:n},error:i,code:ne.ScriptManagerExecutionError}),i}}isRedisReady(){let e=this.cacheClient?.getClient?.();if((0,o.notMissing)(this.cacheClient)&&(0,o.isMissing)(e))return this.logger?.warning({message:`Cache client exists but getClient() returned null - cannot verify Redis readiness`,category:this.name}),!1;let t=e?.isReady&&e?.isOpen;return this.isReady()&&(0,o.notMissing)(this.cacheClient)&&(t??!1)}},SubscriptionManager=class{constructor(e){this.options={getCacheClient:buildRedisClientInstance},this.subscriptionMap=null,this.subscriptionClient=null,this.name=`SubscriptionManager`,this.options={...this.options,...e}}async initialize(e=this.options){let{config:t,getCacheClient:n,logger:r}=e;if(this.logger=r,this.subscriptionMap=new MemoryStore({instantiator:`${e?.instantiator}(${this.name})`,evictionFrequency:e?.subscriptionTTL,staleDataThreshold:e?.staleSubscriptionsThreshold,truncateThreshold:e?.truncateThreshold,truncationPercentage:e?.truncationPercentage,typeGuard:e=>typeof e==`string`,dispose:async e=>{await this.subscriptionClient?.unsubscribe?.(e)}}),(0,o.notMissing)(t))this.subscriptionClient=await n?.(t,this.logger,e?.instantiator)??null,this.logger?.info({message:`${this.name} initialized for ${e.instantiator}.`,category:this.name});else throw Error(`SubscriptionManager requires a Redis client configuration.`)}async subscribe(e,t){this.isReady()||await this.initialize(this.options);let n=await this.subscriptionMap?.getData(e),r=(0,o.getContentHash)(t.toString());return await this.subscriptionMap?.setData({key:e,value:r}),n===r?!0:await this.subscriptionClient?.subscribe?.(e,t)??!1}async unsubscribe(e){return this.isReady()||await this.initialize(this.options),this.subscriptionClient?.unsubscribe?.(e)??!1}isReady(){return(0,o.notMissing)(this.subscriptionClient)&&(0,o.notMissing)(this.subscriptionMap)}close(){this.subscriptionMap?.close(),this.subscriptionMap=null,this.subscriptionClient=null}};const ie=6e4,ae=15e3,oe=!1,se=6e4,ce=15e3,le=1e4,ue=1;let de=function(e){return e.QueueManagerInitializationError=`QueueManagerInitializationError`,e.QueueManagerJoinAndWaitTurnError=`QueueManagerJoinAndWaitTurnError`,e.QueueManagerLengthError=`QueueManagerLengthError`,e.QueueManagerPopError=`QueueManagerPopError`,e}({}),k=function(e){return e.rPush=`rPush`,e.lPush=`lPush`,e.lPop=`lPop`,e.llen=`llen`,e}({});var QueueManager=class extends ScriptManager{constructor(...e){super(...e),this.subscriptionManager=null,this.eventClient=null,this.name=`QueueManager`}async additionalInitialization(){if((0,o.isMissing)(this.redisClientConfig))throw Error(`Redis client configuration is required to initialize QueueManager.`);this.subscriptionManager=new SubscriptionManager({config:this.redisClientConfig,instantiator:this.name,subscriptionTTL:6e4,truncateThreshold:le,truncationPercentage:1}),await this.subscriptionManager?.initialize(),this.eventClient=new EventClient({instantiator:this.name,timeoutResolveValue:!1},{instantiator:this.name,evictionFrequency:ce,truncateThreshold:le,truncationPercentage:1},{instantiator:this.name,evictionFrequency:ce,truncateThreshold:le,truncationPercentage:1}),this.logger?.info({category:this.name,message:`QueueManager initialized.`})}async joinAndWaitTurn(e,t,n,r,i=!0){try{let a=`${e}:${t}`;await this.subscriptionManager?.subscribe(a,async(n,r)=>{if(r.includes(a)&&r.includes(t)){let t=`${e}:${n}`;return this.eventClient?.resolveEvent(t,!0)}});let o=await this.executeScript(n?k.lPush:k.rPush,[e],[t,`60000`])===1;return(!i||!o)&&await this.eventClient?.waitForEvent(a,15e3),await this.eventClient?.deleteEvent(a),await r(e,t)}catch(n){throw n instanceof Error&&this.logger?.error({message:`Error in joinAndWaitTurn`,category:this.name,error:n,code:de.QueueManagerJoinAndWaitTurnError,context:{queueName:e,value:t}}),n}}async pop(e){try{return await this.executeScript(k.lPop,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in pop`,category:this.name,error:t,code:de.QueueManagerPopError,context:{queueName:e}}),t}}async length(e){try{return await this.executeScript(k.llen,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in length`,category:this.name,error:t,code:de.QueueManagerLengthError,context:{queueName:e}}),t}}isReady(){return(0,o.notMissing)(this.subscriptionManager)&&(0,o.notMissing)(this.cacheClient)&&(0,o.notMissing)(this.scriptMap)&&this.scriptMap.size>0}close(){this.subscriptionManager?.close(),this.scriptMap?.clear()}};const fe=5,pe=12e4,me=1e4,he=1,ge=60,_e=90,ve=`__keyevent@0__:`,ye=`${ve}set`,be=`${ve}expire`,A=`${ve}expired`,xe=`${ve}srem`,Se=`config_check_test_key`,Ce=[ye,be,A],we=1,Te=2e4,Ee={mainMaxConcurrency:30};let j=function(e){return e.ConcurrencyManagerInitializationError=`ConcurrencyManagerInitializationError`,e.ConcurrencyManagerRedisEventsEmitError=`ConcurrencyManagerRedisEventsEmitError`,e.ConcurrencyManagerRegistrationFailed=`ConcurrencyManagerRegistrationFailed`,e.ConcurrencyManagerPublishNextItemFailed=`ConcurrencyManagerPublishNextItemFailed`,e.ConcurrencyManagerReleaseRequestFailed=`ConcurrencyManagerReleaseRequestFailed`,e}({}),M=function(e){return e.tryConcurrency=`tryConcurrency`,e.removeFromSet=`removeFromSet`,e.publishNextItem=`publishNextItem`,e}({});const De={[M.tryConcurrency]:`
1
+ var e=Object.create,t=Object.defineProperty,__name=(e,n)=>t(e,`name`,{value:n,configurable:!0}),n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,__commonJSMin=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),__copyProps=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},__toESM=(n,r,a)=>(a=n==null?{}:e(i(n)),__copyProps(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let o=require(`@stackone/utils`),s=require(`redis`);s=__toESM(s);let c=require(`@stackone/expressions`),l=require(`axios`);l=__toESM(l);let u=require(`node:https`);u=__toESM(u);let d=require(`crypto`),f=require(`node:timers`),p=require(`jsonpath-plus`),m=require(`@stackone/redaction`),h=require(`qs`);h=__toESM(h);const createAuthorizationHeaders=e=>{switch(e.type){case`none`:return{};case`basic`:return createBasicAuthorizationHeader(e);case`bearer`:return createBearerAuthorizationHeader(e);case`oauth2`:return createBearerAuthorizationHeader(e);default:throw Error(`Invalid authentication type`)}},createBasicAuthorizationHeader=({username:e=``,password:t=``,encoding:n=`base64`})=>{let r=n;return{authorization:`Basic ${Buffer.from(`${e}:${t}`).toString(r)}`}},createBearerAuthorizationHeader=({token:e,includeBearer:t})=>({authorization:`${t?`Bearer `:``}${e}`});var LockManager=class{constructor(){this.locks=new Map}async withLock(e,t){await this.lock(e);try{return t()}finally{this.unlock(e)}}async lock(e){let t,n=new Promise(e=>t=e),r=this.locks.has(e),i=this.locks.get(e);r&&i?(i.push({lock:n,unlock:t}),await i[i.length-2].lock):this.locks.set(e,[{lock:n,unlock:t}])}unlock(e){let t=this.locks.has(e),n=this.locks.get(e);if(t&&n&&n.length>0){let e=n.shift()?.unlock;e?.()}this.queueLength(e)===0&&this.locks.delete(e)}queueLength(e){return this.locks.get(e)?.length}close(){this.locks.clear()}};const g=1e3,_=100,v=60,y=6e4,b=60,x=y,S=y*10,ee=100,C=10;let w=function(e){return e.MemoryStorePruneError=`MemoryStorePruneError`,e}({});var MemoryStore=class{constructor(e={}){this.lastAccessedAt=Date.now(),this.config=e,this.initialize(e)}initialize(e=this.config){this.instantiator=e?.instantiator??`Unknown`,this.logger=e?.logger,this.dataStore=e?.dataStore??new Map,this.lockManager=e?.lockManager??new LockManager,this.expiryMap=e?.expiryMap??new Map,this.evictionFrequency=e?.evictionFrequency??6e4,this.staleDataThreshold=e?.staleDataThreshold??6e5,this.truncateThreshold=e?.truncateThreshold??100,this.truncationPercentage=e?.truncationPercentage??10,this.typeGuard=e?.typeGuard,this.dispose=e?.dispose,this.startEvictionTask()}async getData(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>this.dataStore.get(e)??null)}async setData({key:e,value:t,cacheTTL:n=60}){if(this.isReady()||this.initialize(),this.updateLastAccessedAt(),(0,o.notMissing)(this.typeGuard)&&!this.typeGuard(t))return!1;let r=n*1e3,i=Date.now()+r;return await this.lockManager.withLock(e,async()=>{((0,o.notMissing)(this.typeGuard)&&this.typeGuard(t)||(0,o.isMissing)(this.typeGuard)&&this.typeGuardBypass(t))&&this.dataStore.set(e,t),this.expiryMap.set(e,i)}),!0}typeGuardBypass(e){return this.logger?.debug({category:`MemoryStore`,message:`${this.instantiator} MemoryStore setting data without type guard - you should probably configure one`}),!0}async delete(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>{if(this.dispose){let t=this.dataStore.get(e);await this.dispose(e,t)}return this.dataStore.delete(e)})}async pruneExpiredKeys(){let e=this.dataStore.size,t=e>=this.truncateThreshold;if(e<=0)return;let n=[],r=0;return this.dataStore.forEach(async(e,i)=>{let a=Date.now(),o=this.expiryMap.get(i)??0,s=this.truncateThreshold*this.truncationPercentage/100;(o<=a||t&&r>=0&&r<=s)&&n.push(this.lockManager.withLock(i,async()=>(this.dispose&&await this.dispose(i,e),this.dataStore.delete(i)))),r++}),await Promise.all(n),{dataStoreSize:e,prunedDataStoreSize:this.dataStore.size}}startEvictionTask(){if((0,o.notMissing)(this.evictionInterval))return;let executePrune=async()=>{let e;try{if(this.lastAccessedAt+this.staleDataThreshold<Date.now()){this.logger?.warning({message:`Closing the ${this.instantiator}'s MemoryStore instance - received no requests for a while.`,category:`MemoryStore`}),this.close();return}e=await this.pruneExpiredKeys(),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}catch(e){e instanceof Error&&this.logger?.error({message:`Error during pruning expired keys:`,category:`MemoryStore`,error:e,code:w.MemoryStorePruneError}),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}finally{if((0,o.notMissing)(e?.dataStoreSize)&&(0,o.notMissing)(e?.prunedDataStoreSize)){let{dataStoreSize:t,prunedDataStoreSize:n}=e,r=t-n;this.logger?.debug({message:`Pruned ${r} expired keys, ${n} remain, scheduling next prune.`,category:`MemoryStore`,context:{instantiator:this.instantiator}})}}};this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}stopEvictionTask(){this.evictionInterval&&=(clearTimeout(this.evictionInterval),void 0)}updateLastAccessedAt(){this.lastAccessedAt=Date.now()}isReady(){return(0,o.notMissing)(this.evictionInterval)&&(0,o.notMissing)(this.dataStore)&&(0,o.notMissing)(this.expiryMap)&&(0,o.notMissing)(this.lockManager)}close(){this.stopEvictionTask(),this.dataStore.clear(),this.expiryMap.clear(),this.lockManager.close()}async listData({partialKey:e,cursor:t,limit:n}){let r=Array.from(this.dataStore.keys()).filter(t=>t.includes(e)),i=[],a=t?parseInt(t,10):0;for(let e=a;e<n+a;e++){let t=r[e];if(!t)break;let a=await this.getData(t);if(a&&i.push(a),i.length>=n)break}return{items:i,cursor:i.length<n?void 0:(a+n).toString()}}};const T=1e3,E=6e4;let D=function(e){return e.EventClientResolveError=`EventClientResolveError`,e}({});var EventClient=class{constructor(e,t,n){this.executorMethodStore=null,this.promiseStore=null,this.eventClientConfig=null,this.executorMethodStoreConfig=null,this.pendingPromiseStoreConfig=null,this.eventClientConfig=e,this.executorMethodStoreConfig=t,this.pendingPromiseStoreConfig=n;let r=e?.instantiator?`${e?.instantiator}(${this.constructor.name})`:this.constructor.name,i={logger:this.logger,dispose:this.defaultExecutorMethodDispose,typeGuard:this.defaultExecutorMethodTypeGuard,...this.executorMethodStoreConfig??{},instantiator:r},a={logger:this.logger,dispose:this.defaultPendingPromiseDispose,typeGuard:this.defaultPendingPromiseTypeGuard,...this.pendingPromiseStoreConfig??{},instantiator:r};this.executorMethodStore=new MemoryStore(i),this.promiseStore=new MemoryStore(a)}async setPendingEvent(e,t){let n={resolve:void 0,reject:void 0},r=new Promise((e,t)=>{n.resolve=e,n.reject=t}),i=t/1e3;await this.executorMethodStore?.setData({key:e,value:n,cacheTTL:i}),await this.promiseStore?.setData({key:e,value:r,cacheTTL:i})}async waitForEvent(e,t){let n=await this.promiseStore?.getData(e);return(0,o.notMissing)(n)?n:(await this.setPendingEvent(e,t),this.getPendingEvent(e))}async getPendingEvent(e){return this.promiseStore?.getData(e)??null}async deleteEvent(e){return(await Promise.all([this.promiseStore?.delete(e),this.executorMethodStore?.delete(e)])).every(Boolean)}async resolveEvent(e,t){try{let n=await this.executorMethodStore?.getData(e);(0,o.isMissing)(n)&&(await this.setPendingEvent(e,this.eventClientConfig?.defaultTimeoutMS??6e4),n=await this.executorMethodStore?.getData(e)),n?.resolve?.(t)}catch(t){t instanceof Error&&this.logger.error({message:`Error handling event for key ${e}: ${t.message}`,category:this.constructor.name,context:{eventKey:e},error:t,code:D.EventClientResolveError})}}async defaultExecutorMethodDispose(e,t){(0,o.notMissing)(t?.resolve)?t.resolve(this.eventClientConfig?.timeoutResolveValue):(0,o.notMissing)(t?.reject)&&t.reject(Error(`Event key: ${e} was not resolved or the event was disposed`))}defaultExecutorMethodTypeGuard(e){return(0,o.isObject)(e)&&e.hasOwnProperty(`resolve`)&&e.hasOwnProperty(`reject`)}async defaultPendingPromiseDispose(e,t){t instanceof Promise&&t?.finally(()=>{})}defaultPendingPromiseTypeGuard(e){return e instanceof Promise}},AsyncSingleton=class{constructor(){this.instance=null,this.initPromise=null,this.retryTimeout=null,this.status=`uninitialized`,this.initOptions=null,this.initArgs=[]}getRetryDelay(){return 5e3}getSingleton(e){throw Error(`getSingleton method not implemented`)}async getInstance(e,...t){return this.instance?this.instance:((0,o.isMissing)(this.initPromise)&&(this.initOptions=e??null,this.initArgs=t,this.initPromise=this.init(e??null,...t)),this.initPromise)}getInstanceIfReady(){return this.instance}isReady(){return this.status===`ready`}hasInitFailed(){return this.status===`failed`}async init(e,...t){try{let n=await this.initInstance(e,...t);return this.instance=n,this.status=`ready`,n}catch(e){throw this.status=`failed`,this.initPromise=null,(0,o.isMissing)(this.retryTimeout)&&(this.retryTimeout=setTimeout(()=>{this.retryTimeout=null,this.getInstance(this.initOptions,...this.initArgs).catch(()=>{})},this.getRetryDelay())),e}}reset(){this.instance=null,this.initPromise=null,this.initOptions=null,this.status=`uninitialized`,this.retryTimeout&&clearTimeout(this.retryTimeout),this.retryTimeout=null}};let O=function(e){return e.RedisClientError=`RedisClientError`,e.RedisClientCommandError=`RedisClientCommandError`,e.RedisClientDeleteError=`RedisClientDeleteError`,e.RedisClientInvalidTTL=`RedisClientInvalidTTL`,e.RedisClientListError=`RedisClientListError`,e.RedisClientNotInitialized=`RedisClientNotInitialized`,e.RedisClientPublishError=`RedisClientPublishError`,e.RedisClientReadError=`RedisClientReadError`,e.RedisClientRedisNotReady=`RedisClientRedisNotReady`,e.RedisClientScriptError=`RedisClientScriptError`,e.RedisClientScriptExecuteError=`RedisClientScriptExecuteError`,e.RedisClientScriptLoadError=`RedisClientScriptLoadError`,e.RedisClientSubscribeError=`RedisClientSubscribeError`,e.RedisClientUnsubscribeError=`RedisClientUnsubscribeError`,e.RedisClientWriteError=`RedisClientWriteError`,e}({});const buildRedisClientInstance=async(e,t,n)=>{try{return await te.build(e,t,n)??void 0}catch(e){let r=e;t?.error({message:`Error building Cache Manager`,error:r,code:O.RedisClientError,category:n??`buildRedisClientInstance`});return}};var te=class RedisClient{#e;#t;static async build({getRedisClient:e=s.createClient,host:t,port:n,tls:r,keepAlive:i=3e4,reconnect:a=!0,database:o},c,l){let u=new RedisClient;u.#t=c;try{u.#e=e({socket:{reconnectStrategy:a?e=>Math.min(e*20,5e3):!1,host:t,port:n,tls:r,keepAlive:i},database:o,disableOfflineQueue:!0});let s=getDefaultRedisListeners(l??`RedisClient`,u.#t);return addRedisEventHandlers(u.#e,s),await u.#e.connect(),u}catch(e){let t=e;return u.#t?.error({message:`Error building Cache Manager.`,error:t,code:O.RedisClientError,category:l??`RedisClient`}),null}}#n(e){try{return JSON.parse(e)}catch{return e}}async getData(e){if(!this.#i())return null;try{let t=await this.#e.get(e);if(!t)return null;let n=this.#n(t);return(0,o.isString)(n)?t:n}catch(e){let t=e;return this.#t?.error({message:`Error getting data`,error:t,code:O.RedisClientReadError,category:RedisClient.name}),null}}async setData({key:e,value:t,cacheTTL:n,groupKey:r}){if(!this.#i())return!1;try{let i=(0,o.isString)(t)?t:JSON.stringify(t);return await this.#e.set(e,i,{EX:n}),(0,o.notMissing)(r)&&await this.#e.sAdd(r,[e]),!0}catch(e){let t=e;return this.#t?.error({message:`Error setting data`,error:t,code:O.RedisClientWriteError,category:RedisClient.name}),!1}}async executeScript({sha1:e,keys:t,args:n}){if(!this.#i())return null;try{return await this.#e.evalSha(e,{keys:t,arguments:n})}catch(e){let t=e;throw this.#t?.error({message:`Error executing script`,error:t,code:O.RedisClientScriptExecuteError,category:RedisClient.name}),t}}async loadScript(e){if(!this.#i())return null;try{return await this.#e.scriptLoad(e)}catch(e){let t=e;return this.#t?.error({message:`Error loading script`,error:t,code:O.RedisClientScriptLoadError,category:RedisClient.name}),null}}async scriptExists(e){if(!this.#i())return e.map(()=>!1);try{return(await this.#e.scriptExists(e)).map(e=>!!e)}catch(t){let n=t;return this.#t?.error({message:`Error checking script existence`,error:n,code:O.RedisClientScriptError,category:RedisClient.name}),e.map(()=>!1)}}async#r(e,t,n){if(!this.#i())return null;if(!Number.isFinite(n)||n<=0)return this.#t?.error({message:`Invalid cacheTTL parameter`,category:RedisClient.name,code:O.RedisClientInvalidTTL}),null;try{let r=[{args:[e,t]},{args:[`expire`,t,n.toString()]}],i=(await this.#e.multiExecutor(r))?.[0];return typeof i==`number`?i:null}catch(t){let n=t;return this.#t?.error({message:`Error executing ${e} operation`,error:n,code:O.RedisClientCommandError,category:RedisClient.name}),null}}async increment(e,t){return this.#r(`incr`,e,t)}async decrement(e,t){return this.#r(`decr`,e,t)}async subscribe(e,t){if(!this.#i())return!1;try{return await this.#e.pSubscribe(e,t),!0}catch(t){let n=t;return this.#t?.error({message:`Error subscribing to ${e}`,error:n,code:O.RedisClientSubscribeError,category:RedisClient.name}),!1}}async unsubscribe(e){if(!this.#i())return!1;try{return await this.#e.pUnsubscribe(e),!0}catch(t){let n=t;return this.#t?.error({message:`Error unsubscribing from ${e}`,error:n,code:O.RedisClientUnsubscribeError,category:RedisClient.name}),!1}}async publish(e,t){if(!this.#i())return null;try{let n=await this.#e.publish(e,t);return n===0&&this.#t?.debug({message:`No subscribers found for channel ${e}`,category:RedisClient.name}),n}catch(t){let n=t;return this.#t?.error({message:`Error publishing to ${e}`,error:n,code:O.RedisClientPublishError,category:RedisClient.name}),null}}getClient(){return this.#i()?this.#e:null}#i(){let e=this.#e.isReady&&this.#e.isOpen;return e||this.#t?.error({message:`Redis Client is not ready.`,category:RedisClient.name,code:O.RedisClientRedisNotReady}),e}async listData({partialKey:e,limit:t,cursor:n}){try{let r=n?parseInt(n,10):0,i=await this.#e.sScan(e,r,{COUNT:t}),a=[];for(let e of i.members){let t=await this.getData(e);(0,o.notMissing)(t)&&a.push(t)}return{items:a,cursor:i.cursor>0?i.cursor.toString():void 0}}catch(e){let t=e;return this.#t?.error({message:`Error listing data`,error:t,code:O.RedisClientListError,category:RedisClient.name}),{items:null}}}async deleteData(e){try{if(!this.#i())return!1;let t=await this.#e.del(e);return t===0&&this.#t?.debug({message:`No keys deleted for ${e}`,category:RedisClient.name}),t>0}catch(e){let t=e;return this.#t?.error({message:`Error deleting data`,error:t,code:O.RedisClientDeleteError,category:RedisClient.name}),!1}}};const addRedisEventHandlers=(e,t)=>{t.forEach(({eventName:t,listener:n})=>{e.on(t,n)})},getDefaultRedisListeners=(e=`RedisClient`,t)=>[{eventName:`error`,listener:n=>{t?.error({message:`Redis client error ${n.message}`,error:n,code:O.RedisClientError,category:e})}},{eventName:`ready`,listener:()=>{t?.info({message:`Redis client ready`,category:e})}},{eventName:`connect`,listener:()=>{t?.info({message:`Redis client connected`,category:e})}},{eventName:`reconnecting`,listener:()=>{t?.info({message:`Redis client reconnecting`,category:e})}},{eventName:`end`,listener:()=>{t?.info({message:`Redis client disconnected`,category:e})}}];let ne=function(e){return e.ScriptManagerExecutionError=`ScriptManagerExecutionError`,e.ScriptManagerLoadingError=`ScriptManagerLoadingError`,e}({});const re=1500;var ScriptManager=class extends AsyncSingleton{constructor(...e){super(...e),this.isInitialConnection=!0,this.reloadInProgress=null,this.lastReloadTime=0}async initInstance({redisClientConfig:e=this.redisClientConfig,cacheClient:t=this.cacheClient,scripts:n=this.scripts,scriptMap:r=this.scriptMap,logger:i=this.logger,additionalArgs:a=this.additionalArgs}){let s=t??await buildRedisClientInstance(e,i,this.name);if((0,o.isMissing)(s))throw Error(`Failed to build Redis client`);return this.redisClientConfig=e,this.logger=i,this.cacheClient=s,this.scripts=n,this.scriptMap=r??new Map,this.additionalArgs=a??[],await this.loadScripts(n,r),this.setupReconnectHandler(),await this.additionalInitialization(...a??[]),this}setupReconnectHandler(){let e=this.cacheClient?.getClient?.();(0,o.notMissing)(e)&&(e.on(`ready`,async()=>{this.isInitialConnection?this.isInitialConnection=!1:(this.logger?.info({message:`Redis reconnected - reloading scripts`,category:this.name}),await this.reloadScripts())}),e.on(`end`,()=>{this.logger?.info({message:`Redis connection closed`,category:this.name})}))}async reloadScripts(){if((0,o.notMissing)(this.reloadInProgress))return this.logger?.info({message:`Script reload already in progress, waiting for completion`,category:this.name}),this.reloadInProgress;if(!((0,o.isMissing)(this.scripts)||Object.keys(this.scripts).length===0)){this.reloadInProgress=this.performReload();try{await this.reloadInProgress}finally{this.reloadInProgress=null}}}async performReload(){this.logger?.info({message:`Reloading ${Object.keys(this.scripts).length} scripts after Redis reconnection`,category:this.name}),this.scriptMap.clear(),await this.loadScripts(this.scripts),this.lastReloadTime=Date.now()}async loadScripts(e,t){if((0,o.notMissing)(t))for(let[e,n]of t)this.scriptMap.set(e,n);let n=Object.entries(e),r=n.map(([e])=>this.scriptMap.get(e)).filter(o.notMissing),i=new Map;if(r.length>0&&(0,o.notMissing)(this.cacheClient?.scriptExists)){let e=await this.cacheClient.scriptExists(r);if((0,o.notMissing)(e)){r.forEach((t,n)=>{i.set(t,e[n]??!1)});let t=e.filter(Boolean).length;t>0&&this.logger?.info({message:`${t}/${r.length} scripts already exist in Redis; skipping load for existing scripts`,category:this.name})}}for(let[e,t]of n){let n=this.scriptMap.get(e);if(n&&i.get(n))continue;let r=await this.cacheClient?.loadScript?.(t);(0,o.notMissing)(r)?this.scriptMap?.set(e,r):this.logger?.error({message:`Error loading script ${e}`,category:this.name,code:ne.ScriptManagerLoadingError})}}async executeScript(e,t,n){if(!this.isRedisReady())return this.logger?.warning({message:`Redis not ready, cannot execute script ${e}`,category:this.name,context:{keys:t,args:n}}),null;let r=this.scriptMap?.get(e);if((0,o.isMissing)(r))throw this.logger?.error({message:`Script for ${e} not found in script map`,category:this.name,code:ne.ScriptManagerExecutionError}),Error(`Script for ${e} not found`);try{return await this.cacheClient?.executeScript?.({sha1:r,keys:t,args:n})??null}catch(i){if(i instanceof Error&&i.message.includes(`NOSCRIPT`)){let i=Date.now()-this.lastReloadTime;if(i<re){let t=re-i;this.logger?.info({message:`Script ${e} not found, reload occurred ${i}ms ago. Waiting ${t}ms before reloading`,category:this.name}),await(0,o.delay)(t)}if(this.logger?.info({message:`Script ${e} not found in Redis, reloading scripts`,category:this.name}),await this.reloadScripts(),r=this.scriptMap?.get(e),(0,o.isMissing)(r))throw Error(`Script for ${e} could not be reloaded`);return await this.cacheClient?.executeScript?.({sha1:r,keys:t,args:n})??null}throw i instanceof Error&&this.logger?.error({message:`Error executing script ${e}: ${i.message}`,category:this.name,context:{keys:t,args:n},error:i,code:ne.ScriptManagerExecutionError}),i}}isRedisReady(){let e=this.cacheClient?.getClient?.();if((0,o.notMissing)(this.cacheClient)&&(0,o.isMissing)(e))return this.logger?.warning({message:`Cache client exists but getClient() returned null - cannot verify Redis readiness`,category:this.name}),!1;let t=e?.isReady&&e?.isOpen;return this.isReady()&&(0,o.notMissing)(this.cacheClient)&&(t??!1)}},SubscriptionManager=class{constructor(e){this.options={getCacheClient:buildRedisClientInstance},this.subscriptionMap=null,this.subscriptionClient=null,this.name=`SubscriptionManager`,this.options={...this.options,...e}}async initialize(e=this.options){let{config:t,getCacheClient:n,logger:r}=e;if(this.logger=r,this.subscriptionMap=new MemoryStore({instantiator:`${e?.instantiator}(${this.name})`,evictionFrequency:e?.subscriptionTTL,staleDataThreshold:e?.staleSubscriptionsThreshold,truncateThreshold:e?.truncateThreshold,truncationPercentage:e?.truncationPercentage,typeGuard:e=>typeof e==`string`,dispose:async e=>{await this.subscriptionClient?.unsubscribe?.(e)}}),(0,o.notMissing)(t))this.subscriptionClient=await n?.(t,this.logger,e?.instantiator)??null,this.logger?.info({message:`${this.name} initialized for ${e.instantiator}.`,category:this.name});else throw Error(`SubscriptionManager requires a Redis client configuration.`)}async subscribe(e,t){this.isReady()||await this.initialize(this.options);let n=await this.subscriptionMap?.getData(e),r=(0,o.getContentHash)(t.toString());return await this.subscriptionMap?.setData({key:e,value:r}),n===r?!0:await this.subscriptionClient?.subscribe?.(e,t)??!1}async unsubscribe(e){return this.isReady()||await this.initialize(this.options),this.subscriptionClient?.unsubscribe?.(e)??!1}isReady(){return(0,o.notMissing)(this.subscriptionClient)&&(0,o.notMissing)(this.subscriptionMap)}close(){this.subscriptionMap?.close(),this.subscriptionMap=null,this.subscriptionClient=null}};const ie=6e4,ae=15e3,oe=!1,se=6e4,ce=15e3,le=1e4,ue=1;let de=function(e){return e.QueueManagerInitializationError=`QueueManagerInitializationError`,e.QueueManagerJoinAndWaitTurnError=`QueueManagerJoinAndWaitTurnError`,e.QueueManagerLengthError=`QueueManagerLengthError`,e.QueueManagerPopError=`QueueManagerPopError`,e}({}),k=function(e){return e.rPush=`rPush`,e.lPush=`lPush`,e.lPop=`lPop`,e.llen=`llen`,e}({});var QueueManager=class extends ScriptManager{constructor(...e){super(...e),this.subscriptionManager=null,this.eventClient=null,this.name=`QueueManager`}async additionalInitialization(){if((0,o.isMissing)(this.redisClientConfig))throw Error(`Redis client configuration is required to initialize QueueManager.`);this.subscriptionManager=new SubscriptionManager({config:this.redisClientConfig,instantiator:this.name,subscriptionTTL:6e4,truncateThreshold:le,truncationPercentage:1}),await this.subscriptionManager?.initialize(),this.eventClient=new EventClient({instantiator:this.name,timeoutResolveValue:!1},{instantiator:this.name,evictionFrequency:ce,truncateThreshold:le,truncationPercentage:1},{instantiator:this.name,evictionFrequency:ce,truncateThreshold:le,truncationPercentage:1}),this.logger?.info({category:this.name,message:`QueueManager initialized.`})}async joinAndWaitTurn(e,t,n,r,i=!0){try{let a=`${e}:${t}`;await this.subscriptionManager?.subscribe(a,async(n,r)=>{if(r.includes(a)&&r.includes(t)){let t=`${e}:${n}`;return this.eventClient?.resolveEvent(t,!0)}});let o=await this.executeScript(n?k.lPush:k.rPush,[e],[t,`60000`])===1;return(!i||!o)&&await this.eventClient?.waitForEvent(a,15e3),await this.eventClient?.deleteEvent(a),await r(e,t)}catch(n){throw n instanceof Error&&this.logger?.error({message:`Error in joinAndWaitTurn`,category:this.name,error:n,code:de.QueueManagerJoinAndWaitTurnError,context:{queueName:e,value:t}}),n}}async pop(e){try{return await this.executeScript(k.lPop,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in pop`,category:this.name,error:t,code:de.QueueManagerPopError,context:{queueName:e}}),t}}async length(e){try{return await this.executeScript(k.llen,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in length`,category:this.name,error:t,code:de.QueueManagerLengthError,context:{queueName:e}}),t}}isReady(){return(0,o.notMissing)(this.subscriptionManager)&&(0,o.notMissing)(this.cacheClient)&&(0,o.notMissing)(this.scriptMap)&&this.scriptMap.size>0}close(){this.subscriptionManager?.close(),this.scriptMap?.clear()}};const fe=5,pe=12e4,me=1e4,he=1,ge=60,_e=90,ve=`__keyevent@0__:`,ye=`${ve}set`,be=`${ve}expire`,A=`${ve}expired`,xe=`${ve}srem`,Se=`config_check_test_key`,Ce=[ye,be,A],we=1,Te=2e4,Ee={mainMaxConcurrency:30};let j=function(e){return e.ConcurrencyManagerInitializationError=`ConcurrencyManagerInitializationError`,e.ConcurrencyManagerRedisEventsEmitError=`ConcurrencyManagerRedisEventsEmitError`,e.ConcurrencyManagerRegistrationFailed=`ConcurrencyManagerRegistrationFailed`,e.ConcurrencyManagerPublishNextItemFailed=`ConcurrencyManagerPublishNextItemFailed`,e.ConcurrencyManagerReleaseRequestFailed=`ConcurrencyManagerReleaseRequestFailed`,e}({}),M=function(e){return e.tryConcurrency=`tryConcurrency`,e.removeFromSet=`removeFromSet`,e.publishNextItem=`publishNextItem`,e}({});const De={[M.tryConcurrency]:`
2
2
  local requestId = KEYS[1]
3
3
  local targetKey = KEYS[2]
4
4
  local queueKey = KEYS[3]
package/dist/index.d.cts CHANGED
@@ -169,6 +169,7 @@ interface RedisClientConfig {
169
169
  host?: string;
170
170
  port?: number;
171
171
  tls?: boolean;
172
+ keepAlive?: number;
172
173
  reconnect?: boolean;
173
174
  database?: number;
174
175
  }
@@ -183,6 +184,7 @@ declare class RedisClient implements ICacheClient<RedisClientType> {
183
184
  host,
184
185
  port,
185
186
  tls,
187
+ keepAlive,
186
188
  reconnect,
187
189
  database
188
190
  }: RedisClientConfig, logger?: ILogger, invoker?: string): Promise<ICacheClient<RedisClientType> | null>;
package/dist/index.d.mts CHANGED
@@ -168,6 +168,7 @@ interface RedisClientConfig {
168
168
  host?: string;
169
169
  port?: number;
170
170
  tls?: boolean;
171
+ keepAlive?: number;
171
172
  reconnect?: boolean;
172
173
  database?: number;
173
174
  }
@@ -182,6 +183,7 @@ declare class RedisClient implements ICacheClient<RedisClientType> {
182
183
  host,
183
184
  port,
184
185
  tls,
186
+ keepAlive,
185
187
  reconnect,
186
188
  database
187
189
  }: RedisClientConfig, logger?: ILogger, invoker?: string): Promise<ICacheClient<RedisClientType> | null>;
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import{n as e,r as t,t as n}from"./chunk-hhuvQGXm.mjs";import{delay as r,exponentialBackoffInMS as i,generateRequestId as a,getContentHash as o,isFunction as s,isFutureUnixTimestamp as c,isMissing as l,isNumber as u,isObject as d,isString as f,notMissing as p,z as m,zStrictObject as h}from"@stackone/utils";import*as g from"redis";import{evaluate as _,safeEvaluate as v}from"@stackone/expressions";import y,{isAxiosError as b}from"axios";import x from"node:https";import{randomUUID as S}from"crypto";import{clearTimeout as C}from"node:timers";import{JSONPath as w}from"jsonpath-plus";import{redactUrl as T}from"@stackone/redaction";import E from"qs";const createAuthorizationHeaders=e=>{switch(e.type){case`none`:return{};case`basic`:return createBasicAuthorizationHeader(e);case`bearer`:return createBearerAuthorizationHeader(e);case`oauth2`:return createBearerAuthorizationHeader(e);default:throw Error(`Invalid authentication type`)}},createBasicAuthorizationHeader=({username:e=``,password:t=``,encoding:n=`base64`})=>{let r=n;return{authorization:`Basic ${Buffer.from(`${e}:${t}`).toString(r)}`}},createBearerAuthorizationHeader=({token:e,includeBearer:t})=>({authorization:`${t?`Bearer `:``}${e}`});var LockManager=class{constructor(){this.locks=new Map}async withLock(e,t){await this.lock(e);try{return t()}finally{this.unlock(e)}}async lock(e){let t,n=new Promise(e=>t=e),r=this.locks.has(e),i=this.locks.get(e);r&&i?(i.push({lock:n,unlock:t}),await i[i.length-2].lock):this.locks.set(e,[{lock:n,unlock:t}])}unlock(e){let t=this.locks.has(e),n=this.locks.get(e);if(t&&n&&n.length>0){let e=n.shift()?.unlock;e?.()}this.queueLength(e)===0&&this.locks.delete(e)}queueLength(e){return this.locks.get(e)?.length}close(){this.locks.clear()}};let D=function(e){return e.MemoryStorePruneError=`MemoryStorePruneError`,e}({});var MemoryStore=class{constructor(e={}){this.lastAccessedAt=Date.now(),this.config=e,this.initialize(e)}initialize(e=this.config){this.instantiator=e?.instantiator??`Unknown`,this.logger=e?.logger,this.dataStore=e?.dataStore??new Map,this.lockManager=e?.lockManager??new LockManager,this.expiryMap=e?.expiryMap??new Map,this.evictionFrequency=e?.evictionFrequency??6e4,this.staleDataThreshold=e?.staleDataThreshold??6e5,this.truncateThreshold=e?.truncateThreshold??100,this.truncationPercentage=e?.truncationPercentage??10,this.typeGuard=e?.typeGuard,this.dispose=e?.dispose,this.startEvictionTask()}async getData(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>this.dataStore.get(e)??null)}async setData({key:e,value:t,cacheTTL:n=60}){if(this.isReady()||this.initialize(),this.updateLastAccessedAt(),p(this.typeGuard)&&!this.typeGuard(t))return!1;let r=n*1e3,i=Date.now()+r;return await this.lockManager.withLock(e,async()=>{(p(this.typeGuard)&&this.typeGuard(t)||l(this.typeGuard)&&this.typeGuardBypass(t))&&this.dataStore.set(e,t),this.expiryMap.set(e,i)}),!0}typeGuardBypass(e){return this.logger?.debug({category:`MemoryStore`,message:`${this.instantiator} MemoryStore setting data without type guard - you should probably configure one`}),!0}async delete(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>{if(this.dispose){let t=this.dataStore.get(e);await this.dispose(e,t)}return this.dataStore.delete(e)})}async pruneExpiredKeys(){let e=this.dataStore.size,t=e>=this.truncateThreshold;if(e<=0)return;let n=[],r=0;return this.dataStore.forEach(async(e,i)=>{let a=Date.now(),o=this.expiryMap.get(i)??0,s=this.truncateThreshold*this.truncationPercentage/100;(o<=a||t&&r>=0&&r<=s)&&n.push(this.lockManager.withLock(i,async()=>(this.dispose&&await this.dispose(i,e),this.dataStore.delete(i)))),r++}),await Promise.all(n),{dataStoreSize:e,prunedDataStoreSize:this.dataStore.size}}startEvictionTask(){if(p(this.evictionInterval))return;let executePrune=async()=>{let e;try{if(this.lastAccessedAt+this.staleDataThreshold<Date.now()){this.logger?.warning({message:`Closing the ${this.instantiator}'s MemoryStore instance - received no requests for a while.`,category:`MemoryStore`}),this.close();return}e=await this.pruneExpiredKeys(),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}catch(e){e instanceof Error&&this.logger?.error({message:`Error during pruning expired keys:`,category:`MemoryStore`,error:e,code:D.MemoryStorePruneError}),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}finally{if(p(e?.dataStoreSize)&&p(e?.prunedDataStoreSize)){let{dataStoreSize:t,prunedDataStoreSize:n}=e,r=t-n;this.logger?.debug({message:`Pruned ${r} expired keys, ${n} remain, scheduling next prune.`,category:`MemoryStore`,context:{instantiator:this.instantiator}})}}};this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}stopEvictionTask(){this.evictionInterval&&=(clearTimeout(this.evictionInterval),void 0)}updateLastAccessedAt(){this.lastAccessedAt=Date.now()}isReady(){return p(this.evictionInterval)&&p(this.dataStore)&&p(this.expiryMap)&&p(this.lockManager)}close(){this.stopEvictionTask(),this.dataStore.clear(),this.expiryMap.clear(),this.lockManager.close()}async listData({partialKey:e,cursor:t,limit:n}){let r=Array.from(this.dataStore.keys()).filter(t=>t.includes(e)),i=[],a=t?parseInt(t,10):0;for(let e=a;e<n+a;e++){let t=r[e];if(!t)break;let a=await this.getData(t);if(a&&i.push(a),i.length>=n)break}return{items:i,cursor:i.length<n?void 0:(a+n).toString()}}};let O=function(e){return e.EventClientResolveError=`EventClientResolveError`,e}({});var EventClient=class{constructor(e,t,n){this.executorMethodStore=null,this.promiseStore=null,this.eventClientConfig=null,this.executorMethodStoreConfig=null,this.pendingPromiseStoreConfig=null,this.eventClientConfig=e,this.executorMethodStoreConfig=t,this.pendingPromiseStoreConfig=n;let r=e?.instantiator?`${e?.instantiator}(${this.constructor.name})`:this.constructor.name,i={logger:this.logger,dispose:this.defaultExecutorMethodDispose,typeGuard:this.defaultExecutorMethodTypeGuard,...this.executorMethodStoreConfig??{},instantiator:r},a={logger:this.logger,dispose:this.defaultPendingPromiseDispose,typeGuard:this.defaultPendingPromiseTypeGuard,...this.pendingPromiseStoreConfig??{},instantiator:r};this.executorMethodStore=new MemoryStore(i),this.promiseStore=new MemoryStore(a)}async setPendingEvent(e,t){let n={resolve:void 0,reject:void 0},r=new Promise((e,t)=>{n.resolve=e,n.reject=t}),i=t/1e3;await this.executorMethodStore?.setData({key:e,value:n,cacheTTL:i}),await this.promiseStore?.setData({key:e,value:r,cacheTTL:i})}async waitForEvent(e,t){let n=await this.promiseStore?.getData(e);return p(n)?n:(await this.setPendingEvent(e,t),this.getPendingEvent(e))}async getPendingEvent(e){return this.promiseStore?.getData(e)??null}async deleteEvent(e){return(await Promise.all([this.promiseStore?.delete(e),this.executorMethodStore?.delete(e)])).every(Boolean)}async resolveEvent(e,t){try{let n=await this.executorMethodStore?.getData(e);l(n)&&(await this.setPendingEvent(e,this.eventClientConfig?.defaultTimeoutMS??6e4),n=await this.executorMethodStore?.getData(e)),n?.resolve?.(t)}catch(t){t instanceof Error&&this.logger.error({message:`Error handling event for key ${e}: ${t.message}`,category:this.constructor.name,context:{eventKey:e},error:t,code:O.EventClientResolveError})}}async defaultExecutorMethodDispose(e,t){p(t?.resolve)?t.resolve(this.eventClientConfig?.timeoutResolveValue):p(t?.reject)&&t.reject(Error(`Event key: ${e} was not resolved or the event was disposed`))}defaultExecutorMethodTypeGuard(e){return d(e)&&e.hasOwnProperty(`resolve`)&&e.hasOwnProperty(`reject`)}async defaultPendingPromiseDispose(e,t){t instanceof Promise&&t?.finally(()=>{})}defaultPendingPromiseTypeGuard(e){return e instanceof Promise}},AsyncSingleton=class{constructor(){this.instance=null,this.initPromise=null,this.retryTimeout=null,this.status=`uninitialized`,this.initOptions=null,this.initArgs=[]}getRetryDelay(){return 5e3}getSingleton(e){throw Error(`getSingleton method not implemented`)}async getInstance(e,...t){return this.instance?this.instance:(l(this.initPromise)&&(this.initOptions=e??null,this.initArgs=t,this.initPromise=this.init(e??null,...t)),this.initPromise)}getInstanceIfReady(){return this.instance}isReady(){return this.status===`ready`}hasInitFailed(){return this.status===`failed`}async init(e,...t){try{let n=await this.initInstance(e,...t);return this.instance=n,this.status=`ready`,n}catch(e){throw this.status=`failed`,this.initPromise=null,l(this.retryTimeout)&&(this.retryTimeout=setTimeout(()=>{this.retryTimeout=null,this.getInstance(this.initOptions,...this.initArgs).catch(()=>{})},this.getRetryDelay())),e}}reset(){this.instance=null,this.initPromise=null,this.initOptions=null,this.status=`uninitialized`,this.retryTimeout&&clearTimeout(this.retryTimeout),this.retryTimeout=null}};let k=function(e){return e.RedisClientError=`RedisClientError`,e.RedisClientCommandError=`RedisClientCommandError`,e.RedisClientDeleteError=`RedisClientDeleteError`,e.RedisClientInvalidTTL=`RedisClientInvalidTTL`,e.RedisClientListError=`RedisClientListError`,e.RedisClientNotInitialized=`RedisClientNotInitialized`,e.RedisClientPublishError=`RedisClientPublishError`,e.RedisClientReadError=`RedisClientReadError`,e.RedisClientRedisNotReady=`RedisClientRedisNotReady`,e.RedisClientScriptError=`RedisClientScriptError`,e.RedisClientScriptExecuteError=`RedisClientScriptExecuteError`,e.RedisClientScriptLoadError=`RedisClientScriptLoadError`,e.RedisClientSubscribeError=`RedisClientSubscribeError`,e.RedisClientUnsubscribeError=`RedisClientUnsubscribeError`,e.RedisClientWriteError=`RedisClientWriteError`,e}({});const buildRedisClientInstance=async(e,t,n)=>{try{return await ee.build(e,t,n)??void 0}catch(e){let r=e;t?.error({message:`Error building Cache Manager`,error:r,code:k.RedisClientError,category:n??`buildRedisClientInstance`});return}};var ee=class RedisClient{#e;#t;static async build({getRedisClient:e=g.createClient,host:t,port:n,tls:r,reconnect:i=!0,database:a},o,s){let c=new RedisClient;c.#t=o;try{c.#e=e({socket:{reconnectStrategy:i?e=>Math.min(e*20,5e3):!1,host:t,port:n,tls:r},database:a,disableOfflineQueue:!0});let o=getDefaultRedisListeners(s??`RedisClient`,c.#t);return addRedisEventHandlers(c.#e,o),await c.#e.connect(),c}catch(e){let t=e;return c.#t?.error({message:`Error building Cache Manager.`,error:t,code:k.RedisClientError,category:s??`RedisClient`}),null}}#n(e){try{return JSON.parse(e)}catch{return e}}async getData(e){if(!this.#i())return null;try{let t=await this.#e.get(e);if(!t)return null;let n=this.#n(t);return f(n)?t:n}catch(e){let t=e;return this.#t?.error({message:`Error getting data`,error:t,code:k.RedisClientReadError,category:RedisClient.name}),null}}async setData({key:e,value:t,cacheTTL:n,groupKey:r}){if(!this.#i())return!1;try{let i=f(t)?t:JSON.stringify(t);return await this.#e.set(e,i,{EX:n}),p(r)&&await this.#e.sAdd(r,[e]),!0}catch(e){let t=e;return this.#t?.error({message:`Error setting data`,error:t,code:k.RedisClientWriteError,category:RedisClient.name}),!1}}async executeScript({sha1:e,keys:t,args:n}){if(!this.#i())return null;try{return await this.#e.evalSha(e,{keys:t,arguments:n})}catch(e){let t=e;throw this.#t?.error({message:`Error executing script`,error:t,code:k.RedisClientScriptExecuteError,category:RedisClient.name}),t}}async loadScript(e){if(!this.#i())return null;try{return await this.#e.scriptLoad(e)}catch(e){let t=e;return this.#t?.error({message:`Error loading script`,error:t,code:k.RedisClientScriptLoadError,category:RedisClient.name}),null}}async scriptExists(e){if(!this.#i())return e.map(()=>!1);try{return(await this.#e.scriptExists(e)).map(e=>!!e)}catch(t){let n=t;return this.#t?.error({message:`Error checking script existence`,error:n,code:k.RedisClientScriptError,category:RedisClient.name}),e.map(()=>!1)}}async#r(e,t,n){if(!this.#i())return null;if(!Number.isFinite(n)||n<=0)return this.#t?.error({message:`Invalid cacheTTL parameter`,category:RedisClient.name,code:k.RedisClientInvalidTTL}),null;try{let r=[{args:[e,t]},{args:[`expire`,t,n.toString()]}],i=(await this.#e.multiExecutor(r))?.[0];return typeof i==`number`?i:null}catch(t){let n=t;return this.#t?.error({message:`Error executing ${e} operation`,error:n,code:k.RedisClientCommandError,category:RedisClient.name}),null}}async increment(e,t){return this.#r(`incr`,e,t)}async decrement(e,t){return this.#r(`decr`,e,t)}async subscribe(e,t){if(!this.#i())return!1;try{return await this.#e.pSubscribe(e,t),!0}catch(t){let n=t;return this.#t?.error({message:`Error subscribing to ${e}`,error:n,code:k.RedisClientSubscribeError,category:RedisClient.name}),!1}}async unsubscribe(e){if(!this.#i())return!1;try{return await this.#e.pUnsubscribe(e),!0}catch(t){let n=t;return this.#t?.error({message:`Error unsubscribing from ${e}`,error:n,code:k.RedisClientUnsubscribeError,category:RedisClient.name}),!1}}async publish(e,t){if(!this.#i())return null;try{let n=await this.#e.publish(e,t);return n===0&&this.#t?.debug({message:`No subscribers found for channel ${e}`,category:RedisClient.name}),n}catch(t){let n=t;return this.#t?.error({message:`Error publishing to ${e}`,error:n,code:k.RedisClientPublishError,category:RedisClient.name}),null}}getClient(){return this.#i()?this.#e:null}#i(){let e=this.#e.isReady&&this.#e.isOpen;return e||this.#t?.error({message:`Redis Client is not ready.`,category:RedisClient.name,code:k.RedisClientRedisNotReady}),e}async listData({partialKey:e,limit:t,cursor:n}){try{let r=n?parseInt(n,10):0,i=await this.#e.sScan(e,r,{COUNT:t}),a=[];for(let e of i.members){let t=await this.getData(e);p(t)&&a.push(t)}return{items:a,cursor:i.cursor>0?i.cursor.toString():void 0}}catch(e){let t=e;return this.#t?.error({message:`Error listing data`,error:t,code:k.RedisClientListError,category:RedisClient.name}),{items:null}}}async deleteData(e){try{if(!this.#i())return!1;let t=await this.#e.del(e);return t===0&&this.#t?.debug({message:`No keys deleted for ${e}`,category:RedisClient.name}),t>0}catch(e){let t=e;return this.#t?.error({message:`Error deleting data`,error:t,code:k.RedisClientDeleteError,category:RedisClient.name}),!1}}};const addRedisEventHandlers=(e,t)=>{t.forEach(({eventName:t,listener:n})=>{e.on(t,n)})},getDefaultRedisListeners=(e=`RedisClient`,t)=>[{eventName:`error`,listener:n=>{t?.error({message:`Redis client error ${n.message}`,error:n,code:k.RedisClientError,category:e})}},{eventName:`ready`,listener:()=>{t?.info({message:`Redis client ready`,category:e})}},{eventName:`connect`,listener:()=>{t?.info({message:`Redis client connected`,category:e})}},{eventName:`reconnecting`,listener:()=>{t?.info({message:`Redis client reconnecting`,category:e})}},{eventName:`end`,listener:()=>{t?.info({message:`Redis client disconnected`,category:e})}}];let te=function(e){return e.ScriptManagerExecutionError=`ScriptManagerExecutionError`,e.ScriptManagerLoadingError=`ScriptManagerLoadingError`,e}({});const ne=1500;var ScriptManager=class extends AsyncSingleton{constructor(...e){super(...e),this.isInitialConnection=!0,this.reloadInProgress=null,this.lastReloadTime=0}async initInstance({redisClientConfig:e=this.redisClientConfig,cacheClient:t=this.cacheClient,scripts:n=this.scripts,scriptMap:r=this.scriptMap,logger:i=this.logger,additionalArgs:a=this.additionalArgs}){let o=t??await buildRedisClientInstance(e,i,this.name);if(l(o))throw Error(`Failed to build Redis client`);return this.redisClientConfig=e,this.logger=i,this.cacheClient=o,this.scripts=n,this.scriptMap=r??new Map,this.additionalArgs=a??[],await this.loadScripts(n,r),this.setupReconnectHandler(),await this.additionalInitialization(...a??[]),this}setupReconnectHandler(){let e=this.cacheClient?.getClient?.();p(e)&&(e.on(`ready`,async()=>{this.isInitialConnection?this.isInitialConnection=!1:(this.logger?.info({message:`Redis reconnected - reloading scripts`,category:this.name}),await this.reloadScripts())}),e.on(`end`,()=>{this.logger?.info({message:`Redis connection closed`,category:this.name})}))}async reloadScripts(){if(p(this.reloadInProgress))return this.logger?.info({message:`Script reload already in progress, waiting for completion`,category:this.name}),this.reloadInProgress;if(!(l(this.scripts)||Object.keys(this.scripts).length===0)){this.reloadInProgress=this.performReload();try{await this.reloadInProgress}finally{this.reloadInProgress=null}}}async performReload(){this.logger?.info({message:`Reloading ${Object.keys(this.scripts).length} scripts after Redis reconnection`,category:this.name}),this.scriptMap.clear(),await this.loadScripts(this.scripts),this.lastReloadTime=Date.now()}async loadScripts(e,t){if(p(t))for(let[e,n]of t)this.scriptMap.set(e,n);let n=Object.entries(e),r=n.map(([e])=>this.scriptMap.get(e)).filter(p),i=new Map;if(r.length>0&&p(this.cacheClient?.scriptExists)){let e=await this.cacheClient.scriptExists(r);if(p(e)){r.forEach((t,n)=>{i.set(t,e[n]??!1)});let t=e.filter(Boolean).length;t>0&&this.logger?.info({message:`${t}/${r.length} scripts already exist in Redis; skipping load for existing scripts`,category:this.name})}}for(let[e,t]of n){let n=this.scriptMap.get(e);if(n&&i.get(n))continue;let r=await this.cacheClient?.loadScript?.(t);p(r)?this.scriptMap?.set(e,r):this.logger?.error({message:`Error loading script ${e}`,category:this.name,code:te.ScriptManagerLoadingError})}}async executeScript(e,t,n){if(!this.isRedisReady())return this.logger?.warning({message:`Redis not ready, cannot execute script ${e}`,category:this.name,context:{keys:t,args:n}}),null;let i=this.scriptMap?.get(e);if(l(i))throw this.logger?.error({message:`Script for ${e} not found in script map`,category:this.name,code:te.ScriptManagerExecutionError}),Error(`Script for ${e} not found`);try{return await this.cacheClient?.executeScript?.({sha1:i,keys:t,args:n})??null}catch(a){if(a instanceof Error&&a.message.includes(`NOSCRIPT`)){let a=Date.now()-this.lastReloadTime;if(a<ne){let t=ne-a;this.logger?.info({message:`Script ${e} not found, reload occurred ${a}ms ago. Waiting ${t}ms before reloading`,category:this.name}),await r(t)}if(this.logger?.info({message:`Script ${e} not found in Redis, reloading scripts`,category:this.name}),await this.reloadScripts(),i=this.scriptMap?.get(e),l(i))throw Error(`Script for ${e} could not be reloaded`);return await this.cacheClient?.executeScript?.({sha1:i,keys:t,args:n})??null}throw a instanceof Error&&this.logger?.error({message:`Error executing script ${e}: ${a.message}`,category:this.name,context:{keys:t,args:n},error:a,code:te.ScriptManagerExecutionError}),a}}isRedisReady(){let e=this.cacheClient?.getClient?.();if(p(this.cacheClient)&&l(e))return this.logger?.warning({message:`Cache client exists but getClient() returned null - cannot verify Redis readiness`,category:this.name}),!1;let t=e?.isReady&&e?.isOpen;return this.isReady()&&p(this.cacheClient)&&(t??!1)}},SubscriptionManager=class{constructor(e){this.options={getCacheClient:buildRedisClientInstance},this.subscriptionMap=null,this.subscriptionClient=null,this.name=`SubscriptionManager`,this.options={...this.options,...e}}async initialize(e=this.options){let{config:t,getCacheClient:n,logger:r}=e;if(this.logger=r,this.subscriptionMap=new MemoryStore({instantiator:`${e?.instantiator}(${this.name})`,evictionFrequency:e?.subscriptionTTL,staleDataThreshold:e?.staleSubscriptionsThreshold,truncateThreshold:e?.truncateThreshold,truncationPercentage:e?.truncationPercentage,typeGuard:e=>typeof e==`string`,dispose:async e=>{await this.subscriptionClient?.unsubscribe?.(e)}}),p(t))this.subscriptionClient=await n?.(t,this.logger,e?.instantiator)??null,this.logger?.info({message:`${this.name} initialized for ${e.instantiator}.`,category:this.name});else throw Error(`SubscriptionManager requires a Redis client configuration.`)}async subscribe(e,t){this.isReady()||await this.initialize(this.options);let n=await this.subscriptionMap?.getData(e),r=o(t.toString());return await this.subscriptionMap?.setData({key:e,value:r}),n===r?!0:await this.subscriptionClient?.subscribe?.(e,t)??!1}async unsubscribe(e){return this.isReady()||await this.initialize(this.options),this.subscriptionClient?.unsubscribe?.(e)??!1}isReady(){return p(this.subscriptionClient)&&p(this.subscriptionMap)}close(){this.subscriptionMap?.close(),this.subscriptionMap=null,this.subscriptionClient=null}};const re=15e3,ie=1e4;let ae=function(e){return e.QueueManagerInitializationError=`QueueManagerInitializationError`,e.QueueManagerJoinAndWaitTurnError=`QueueManagerJoinAndWaitTurnError`,e.QueueManagerLengthError=`QueueManagerLengthError`,e.QueueManagerPopError=`QueueManagerPopError`,e}({}),A=function(e){return e.rPush=`rPush`,e.lPush=`lPush`,e.lPop=`lPop`,e.llen=`llen`,e}({});var QueueManager=class extends ScriptManager{constructor(...e){super(...e),this.subscriptionManager=null,this.eventClient=null,this.name=`QueueManager`}async additionalInitialization(){if(l(this.redisClientConfig))throw Error(`Redis client configuration is required to initialize QueueManager.`);this.subscriptionManager=new SubscriptionManager({config:this.redisClientConfig,instantiator:this.name,subscriptionTTL:6e4,truncateThreshold:ie,truncationPercentage:1}),await this.subscriptionManager?.initialize(),this.eventClient=new EventClient({instantiator:this.name,timeoutResolveValue:!1},{instantiator:this.name,evictionFrequency:re,truncateThreshold:ie,truncationPercentage:1},{instantiator:this.name,evictionFrequency:re,truncateThreshold:ie,truncationPercentage:1}),this.logger?.info({category:this.name,message:`QueueManager initialized.`})}async joinAndWaitTurn(e,t,n,r,i=!0){try{let a=`${e}:${t}`;await this.subscriptionManager?.subscribe(a,async(n,r)=>{if(r.includes(a)&&r.includes(t)){let t=`${e}:${n}`;return this.eventClient?.resolveEvent(t,!0)}});let o=await this.executeScript(n?A.lPush:A.rPush,[e],[t,`60000`])===1;return(!i||!o)&&await this.eventClient?.waitForEvent(a,15e3),await this.eventClient?.deleteEvent(a),await r(e,t)}catch(n){throw n instanceof Error&&this.logger?.error({message:`Error in joinAndWaitTurn`,category:this.name,error:n,code:ae.QueueManagerJoinAndWaitTurnError,context:{queueName:e,value:t}}),n}}async pop(e){try{return await this.executeScript(A.lPop,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in pop`,category:this.name,error:t,code:ae.QueueManagerPopError,context:{queueName:e}}),t}}async length(e){try{return await this.executeScript(A.llen,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in length`,category:this.name,error:t,code:ae.QueueManagerLengthError,context:{queueName:e}}),t}}isReady(){return p(this.subscriptionManager)&&p(this.cacheClient)&&p(this.scriptMap)&&this.scriptMap.size>0}close(){this.subscriptionManager?.close(),this.scriptMap?.clear()}};const j=`__keyevent@0__:`,oe=`${j}set`,se=`${j}expire`,M=`${j}expired`,ce=`${j}srem`,le=[oe,se,M],ue={mainMaxConcurrency:30};let N=function(e){return e.ConcurrencyManagerInitializationError=`ConcurrencyManagerInitializationError`,e.ConcurrencyManagerRedisEventsEmitError=`ConcurrencyManagerRedisEventsEmitError`,e.ConcurrencyManagerRegistrationFailed=`ConcurrencyManagerRegistrationFailed`,e.ConcurrencyManagerPublishNextItemFailed=`ConcurrencyManagerPublishNextItemFailed`,e.ConcurrencyManagerReleaseRequestFailed=`ConcurrencyManagerReleaseRequestFailed`,e}({}),P=function(e){return e.tryConcurrency=`tryConcurrency`,e.removeFromSet=`removeFromSet`,e.publishNextItem=`publishNextItem`,e}({});const de={[P.tryConcurrency]:`
1
+ import{n as e,r as t,t as n}from"./chunk-hhuvQGXm.mjs";import{delay as r,exponentialBackoffInMS as i,generateRequestId as a,getContentHash as o,isFunction as s,isFutureUnixTimestamp as c,isMissing as l,isNumber as u,isObject as d,isString as f,notMissing as p,z as m,zStrictObject as h}from"@stackone/utils";import*as g from"redis";import{evaluate as _,safeEvaluate as v}from"@stackone/expressions";import y,{isAxiosError as b}from"axios";import x from"node:https";import{randomUUID as S}from"crypto";import{clearTimeout as C}from"node:timers";import{JSONPath as w}from"jsonpath-plus";import{redactUrl as T}from"@stackone/redaction";import E from"qs";const createAuthorizationHeaders=e=>{switch(e.type){case`none`:return{};case`basic`:return createBasicAuthorizationHeader(e);case`bearer`:return createBearerAuthorizationHeader(e);case`oauth2`:return createBearerAuthorizationHeader(e);default:throw Error(`Invalid authentication type`)}},createBasicAuthorizationHeader=({username:e=``,password:t=``,encoding:n=`base64`})=>{let r=n;return{authorization:`Basic ${Buffer.from(`${e}:${t}`).toString(r)}`}},createBearerAuthorizationHeader=({token:e,includeBearer:t})=>({authorization:`${t?`Bearer `:``}${e}`});var LockManager=class{constructor(){this.locks=new Map}async withLock(e,t){await this.lock(e);try{return t()}finally{this.unlock(e)}}async lock(e){let t,n=new Promise(e=>t=e),r=this.locks.has(e),i=this.locks.get(e);r&&i?(i.push({lock:n,unlock:t}),await i[i.length-2].lock):this.locks.set(e,[{lock:n,unlock:t}])}unlock(e){let t=this.locks.has(e),n=this.locks.get(e);if(t&&n&&n.length>0){let e=n.shift()?.unlock;e?.()}this.queueLength(e)===0&&this.locks.delete(e)}queueLength(e){return this.locks.get(e)?.length}close(){this.locks.clear()}};let D=function(e){return e.MemoryStorePruneError=`MemoryStorePruneError`,e}({});var MemoryStore=class{constructor(e={}){this.lastAccessedAt=Date.now(),this.config=e,this.initialize(e)}initialize(e=this.config){this.instantiator=e?.instantiator??`Unknown`,this.logger=e?.logger,this.dataStore=e?.dataStore??new Map,this.lockManager=e?.lockManager??new LockManager,this.expiryMap=e?.expiryMap??new Map,this.evictionFrequency=e?.evictionFrequency??6e4,this.staleDataThreshold=e?.staleDataThreshold??6e5,this.truncateThreshold=e?.truncateThreshold??100,this.truncationPercentage=e?.truncationPercentage??10,this.typeGuard=e?.typeGuard,this.dispose=e?.dispose,this.startEvictionTask()}async getData(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>this.dataStore.get(e)??null)}async setData({key:e,value:t,cacheTTL:n=60}){if(this.isReady()||this.initialize(),this.updateLastAccessedAt(),p(this.typeGuard)&&!this.typeGuard(t))return!1;let r=n*1e3,i=Date.now()+r;return await this.lockManager.withLock(e,async()=>{(p(this.typeGuard)&&this.typeGuard(t)||l(this.typeGuard)&&this.typeGuardBypass(t))&&this.dataStore.set(e,t),this.expiryMap.set(e,i)}),!0}typeGuardBypass(e){return this.logger?.debug({category:`MemoryStore`,message:`${this.instantiator} MemoryStore setting data without type guard - you should probably configure one`}),!0}async delete(e){return this.isReady()||this.initialize(),this.updateLastAccessedAt(),this.lockManager.withLock(e,async()=>{if(this.dispose){let t=this.dataStore.get(e);await this.dispose(e,t)}return this.dataStore.delete(e)})}async pruneExpiredKeys(){let e=this.dataStore.size,t=e>=this.truncateThreshold;if(e<=0)return;let n=[],r=0;return this.dataStore.forEach(async(e,i)=>{let a=Date.now(),o=this.expiryMap.get(i)??0,s=this.truncateThreshold*this.truncationPercentage/100;(o<=a||t&&r>=0&&r<=s)&&n.push(this.lockManager.withLock(i,async()=>(this.dispose&&await this.dispose(i,e),this.dataStore.delete(i)))),r++}),await Promise.all(n),{dataStoreSize:e,prunedDataStoreSize:this.dataStore.size}}startEvictionTask(){if(p(this.evictionInterval))return;let executePrune=async()=>{let e;try{if(this.lastAccessedAt+this.staleDataThreshold<Date.now()){this.logger?.warning({message:`Closing the ${this.instantiator}'s MemoryStore instance - received no requests for a while.`,category:`MemoryStore`}),this.close();return}e=await this.pruneExpiredKeys(),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}catch(e){e instanceof Error&&this.logger?.error({message:`Error during pruning expired keys:`,category:`MemoryStore`,error:e,code:D.MemoryStorePruneError}),this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}finally{if(p(e?.dataStoreSize)&&p(e?.prunedDataStoreSize)){let{dataStoreSize:t,prunedDataStoreSize:n}=e,r=t-n;this.logger?.debug({message:`Pruned ${r} expired keys, ${n} remain, scheduling next prune.`,category:`MemoryStore`,context:{instantiator:this.instantiator}})}}};this.evictionInterval=setTimeout(executePrune,this.evictionFrequency)}stopEvictionTask(){this.evictionInterval&&=(clearTimeout(this.evictionInterval),void 0)}updateLastAccessedAt(){this.lastAccessedAt=Date.now()}isReady(){return p(this.evictionInterval)&&p(this.dataStore)&&p(this.expiryMap)&&p(this.lockManager)}close(){this.stopEvictionTask(),this.dataStore.clear(),this.expiryMap.clear(),this.lockManager.close()}async listData({partialKey:e,cursor:t,limit:n}){let r=Array.from(this.dataStore.keys()).filter(t=>t.includes(e)),i=[],a=t?parseInt(t,10):0;for(let e=a;e<n+a;e++){let t=r[e];if(!t)break;let a=await this.getData(t);if(a&&i.push(a),i.length>=n)break}return{items:i,cursor:i.length<n?void 0:(a+n).toString()}}};let O=function(e){return e.EventClientResolveError=`EventClientResolveError`,e}({});var EventClient=class{constructor(e,t,n){this.executorMethodStore=null,this.promiseStore=null,this.eventClientConfig=null,this.executorMethodStoreConfig=null,this.pendingPromiseStoreConfig=null,this.eventClientConfig=e,this.executorMethodStoreConfig=t,this.pendingPromiseStoreConfig=n;let r=e?.instantiator?`${e?.instantiator}(${this.constructor.name})`:this.constructor.name,i={logger:this.logger,dispose:this.defaultExecutorMethodDispose,typeGuard:this.defaultExecutorMethodTypeGuard,...this.executorMethodStoreConfig??{},instantiator:r},a={logger:this.logger,dispose:this.defaultPendingPromiseDispose,typeGuard:this.defaultPendingPromiseTypeGuard,...this.pendingPromiseStoreConfig??{},instantiator:r};this.executorMethodStore=new MemoryStore(i),this.promiseStore=new MemoryStore(a)}async setPendingEvent(e,t){let n={resolve:void 0,reject:void 0},r=new Promise((e,t)=>{n.resolve=e,n.reject=t}),i=t/1e3;await this.executorMethodStore?.setData({key:e,value:n,cacheTTL:i}),await this.promiseStore?.setData({key:e,value:r,cacheTTL:i})}async waitForEvent(e,t){let n=await this.promiseStore?.getData(e);return p(n)?n:(await this.setPendingEvent(e,t),this.getPendingEvent(e))}async getPendingEvent(e){return this.promiseStore?.getData(e)??null}async deleteEvent(e){return(await Promise.all([this.promiseStore?.delete(e),this.executorMethodStore?.delete(e)])).every(Boolean)}async resolveEvent(e,t){try{let n=await this.executorMethodStore?.getData(e);l(n)&&(await this.setPendingEvent(e,this.eventClientConfig?.defaultTimeoutMS??6e4),n=await this.executorMethodStore?.getData(e)),n?.resolve?.(t)}catch(t){t instanceof Error&&this.logger.error({message:`Error handling event for key ${e}: ${t.message}`,category:this.constructor.name,context:{eventKey:e},error:t,code:O.EventClientResolveError})}}async defaultExecutorMethodDispose(e,t){p(t?.resolve)?t.resolve(this.eventClientConfig?.timeoutResolveValue):p(t?.reject)&&t.reject(Error(`Event key: ${e} was not resolved or the event was disposed`))}defaultExecutorMethodTypeGuard(e){return d(e)&&e.hasOwnProperty(`resolve`)&&e.hasOwnProperty(`reject`)}async defaultPendingPromiseDispose(e,t){t instanceof Promise&&t?.finally(()=>{})}defaultPendingPromiseTypeGuard(e){return e instanceof Promise}},AsyncSingleton=class{constructor(){this.instance=null,this.initPromise=null,this.retryTimeout=null,this.status=`uninitialized`,this.initOptions=null,this.initArgs=[]}getRetryDelay(){return 5e3}getSingleton(e){throw Error(`getSingleton method not implemented`)}async getInstance(e,...t){return this.instance?this.instance:(l(this.initPromise)&&(this.initOptions=e??null,this.initArgs=t,this.initPromise=this.init(e??null,...t)),this.initPromise)}getInstanceIfReady(){return this.instance}isReady(){return this.status===`ready`}hasInitFailed(){return this.status===`failed`}async init(e,...t){try{let n=await this.initInstance(e,...t);return this.instance=n,this.status=`ready`,n}catch(e){throw this.status=`failed`,this.initPromise=null,l(this.retryTimeout)&&(this.retryTimeout=setTimeout(()=>{this.retryTimeout=null,this.getInstance(this.initOptions,...this.initArgs).catch(()=>{})},this.getRetryDelay())),e}}reset(){this.instance=null,this.initPromise=null,this.initOptions=null,this.status=`uninitialized`,this.retryTimeout&&clearTimeout(this.retryTimeout),this.retryTimeout=null}};let k=function(e){return e.RedisClientError=`RedisClientError`,e.RedisClientCommandError=`RedisClientCommandError`,e.RedisClientDeleteError=`RedisClientDeleteError`,e.RedisClientInvalidTTL=`RedisClientInvalidTTL`,e.RedisClientListError=`RedisClientListError`,e.RedisClientNotInitialized=`RedisClientNotInitialized`,e.RedisClientPublishError=`RedisClientPublishError`,e.RedisClientReadError=`RedisClientReadError`,e.RedisClientRedisNotReady=`RedisClientRedisNotReady`,e.RedisClientScriptError=`RedisClientScriptError`,e.RedisClientScriptExecuteError=`RedisClientScriptExecuteError`,e.RedisClientScriptLoadError=`RedisClientScriptLoadError`,e.RedisClientSubscribeError=`RedisClientSubscribeError`,e.RedisClientUnsubscribeError=`RedisClientUnsubscribeError`,e.RedisClientWriteError=`RedisClientWriteError`,e}({});const buildRedisClientInstance=async(e,t,n)=>{try{return await ee.build(e,t,n)??void 0}catch(e){let r=e;t?.error({message:`Error building Cache Manager`,error:r,code:k.RedisClientError,category:n??`buildRedisClientInstance`});return}};var ee=class RedisClient{#e;#t;static async build({getRedisClient:e=g.createClient,host:t,port:n,tls:r,keepAlive:i=3e4,reconnect:a=!0,database:o},s,c){let l=new RedisClient;l.#t=s;try{l.#e=e({socket:{reconnectStrategy:a?e=>Math.min(e*20,5e3):!1,host:t,port:n,tls:r,keepAlive:i},database:o,disableOfflineQueue:!0});let s=getDefaultRedisListeners(c??`RedisClient`,l.#t);return addRedisEventHandlers(l.#e,s),await l.#e.connect(),l}catch(e){let t=e;return l.#t?.error({message:`Error building Cache Manager.`,error:t,code:k.RedisClientError,category:c??`RedisClient`}),null}}#n(e){try{return JSON.parse(e)}catch{return e}}async getData(e){if(!this.#i())return null;try{let t=await this.#e.get(e);if(!t)return null;let n=this.#n(t);return f(n)?t:n}catch(e){let t=e;return this.#t?.error({message:`Error getting data`,error:t,code:k.RedisClientReadError,category:RedisClient.name}),null}}async setData({key:e,value:t,cacheTTL:n,groupKey:r}){if(!this.#i())return!1;try{let i=f(t)?t:JSON.stringify(t);return await this.#e.set(e,i,{EX:n}),p(r)&&await this.#e.sAdd(r,[e]),!0}catch(e){let t=e;return this.#t?.error({message:`Error setting data`,error:t,code:k.RedisClientWriteError,category:RedisClient.name}),!1}}async executeScript({sha1:e,keys:t,args:n}){if(!this.#i())return null;try{return await this.#e.evalSha(e,{keys:t,arguments:n})}catch(e){let t=e;throw this.#t?.error({message:`Error executing script`,error:t,code:k.RedisClientScriptExecuteError,category:RedisClient.name}),t}}async loadScript(e){if(!this.#i())return null;try{return await this.#e.scriptLoad(e)}catch(e){let t=e;return this.#t?.error({message:`Error loading script`,error:t,code:k.RedisClientScriptLoadError,category:RedisClient.name}),null}}async scriptExists(e){if(!this.#i())return e.map(()=>!1);try{return(await this.#e.scriptExists(e)).map(e=>!!e)}catch(t){let n=t;return this.#t?.error({message:`Error checking script existence`,error:n,code:k.RedisClientScriptError,category:RedisClient.name}),e.map(()=>!1)}}async#r(e,t,n){if(!this.#i())return null;if(!Number.isFinite(n)||n<=0)return this.#t?.error({message:`Invalid cacheTTL parameter`,category:RedisClient.name,code:k.RedisClientInvalidTTL}),null;try{let r=[{args:[e,t]},{args:[`expire`,t,n.toString()]}],i=(await this.#e.multiExecutor(r))?.[0];return typeof i==`number`?i:null}catch(t){let n=t;return this.#t?.error({message:`Error executing ${e} operation`,error:n,code:k.RedisClientCommandError,category:RedisClient.name}),null}}async increment(e,t){return this.#r(`incr`,e,t)}async decrement(e,t){return this.#r(`decr`,e,t)}async subscribe(e,t){if(!this.#i())return!1;try{return await this.#e.pSubscribe(e,t),!0}catch(t){let n=t;return this.#t?.error({message:`Error subscribing to ${e}`,error:n,code:k.RedisClientSubscribeError,category:RedisClient.name}),!1}}async unsubscribe(e){if(!this.#i())return!1;try{return await this.#e.pUnsubscribe(e),!0}catch(t){let n=t;return this.#t?.error({message:`Error unsubscribing from ${e}`,error:n,code:k.RedisClientUnsubscribeError,category:RedisClient.name}),!1}}async publish(e,t){if(!this.#i())return null;try{let n=await this.#e.publish(e,t);return n===0&&this.#t?.debug({message:`No subscribers found for channel ${e}`,category:RedisClient.name}),n}catch(t){let n=t;return this.#t?.error({message:`Error publishing to ${e}`,error:n,code:k.RedisClientPublishError,category:RedisClient.name}),null}}getClient(){return this.#i()?this.#e:null}#i(){let e=this.#e.isReady&&this.#e.isOpen;return e||this.#t?.error({message:`Redis Client is not ready.`,category:RedisClient.name,code:k.RedisClientRedisNotReady}),e}async listData({partialKey:e,limit:t,cursor:n}){try{let r=n?parseInt(n,10):0,i=await this.#e.sScan(e,r,{COUNT:t}),a=[];for(let e of i.members){let t=await this.getData(e);p(t)&&a.push(t)}return{items:a,cursor:i.cursor>0?i.cursor.toString():void 0}}catch(e){let t=e;return this.#t?.error({message:`Error listing data`,error:t,code:k.RedisClientListError,category:RedisClient.name}),{items:null}}}async deleteData(e){try{if(!this.#i())return!1;let t=await this.#e.del(e);return t===0&&this.#t?.debug({message:`No keys deleted for ${e}`,category:RedisClient.name}),t>0}catch(e){let t=e;return this.#t?.error({message:`Error deleting data`,error:t,code:k.RedisClientDeleteError,category:RedisClient.name}),!1}}};const addRedisEventHandlers=(e,t)=>{t.forEach(({eventName:t,listener:n})=>{e.on(t,n)})},getDefaultRedisListeners=(e=`RedisClient`,t)=>[{eventName:`error`,listener:n=>{t?.error({message:`Redis client error ${n.message}`,error:n,code:k.RedisClientError,category:e})}},{eventName:`ready`,listener:()=>{t?.info({message:`Redis client ready`,category:e})}},{eventName:`connect`,listener:()=>{t?.info({message:`Redis client connected`,category:e})}},{eventName:`reconnecting`,listener:()=>{t?.info({message:`Redis client reconnecting`,category:e})}},{eventName:`end`,listener:()=>{t?.info({message:`Redis client disconnected`,category:e})}}];let te=function(e){return e.ScriptManagerExecutionError=`ScriptManagerExecutionError`,e.ScriptManagerLoadingError=`ScriptManagerLoadingError`,e}({});const ne=1500;var ScriptManager=class extends AsyncSingleton{constructor(...e){super(...e),this.isInitialConnection=!0,this.reloadInProgress=null,this.lastReloadTime=0}async initInstance({redisClientConfig:e=this.redisClientConfig,cacheClient:t=this.cacheClient,scripts:n=this.scripts,scriptMap:r=this.scriptMap,logger:i=this.logger,additionalArgs:a=this.additionalArgs}){let o=t??await buildRedisClientInstance(e,i,this.name);if(l(o))throw Error(`Failed to build Redis client`);return this.redisClientConfig=e,this.logger=i,this.cacheClient=o,this.scripts=n,this.scriptMap=r??new Map,this.additionalArgs=a??[],await this.loadScripts(n,r),this.setupReconnectHandler(),await this.additionalInitialization(...a??[]),this}setupReconnectHandler(){let e=this.cacheClient?.getClient?.();p(e)&&(e.on(`ready`,async()=>{this.isInitialConnection?this.isInitialConnection=!1:(this.logger?.info({message:`Redis reconnected - reloading scripts`,category:this.name}),await this.reloadScripts())}),e.on(`end`,()=>{this.logger?.info({message:`Redis connection closed`,category:this.name})}))}async reloadScripts(){if(p(this.reloadInProgress))return this.logger?.info({message:`Script reload already in progress, waiting for completion`,category:this.name}),this.reloadInProgress;if(!(l(this.scripts)||Object.keys(this.scripts).length===0)){this.reloadInProgress=this.performReload();try{await this.reloadInProgress}finally{this.reloadInProgress=null}}}async performReload(){this.logger?.info({message:`Reloading ${Object.keys(this.scripts).length} scripts after Redis reconnection`,category:this.name}),this.scriptMap.clear(),await this.loadScripts(this.scripts),this.lastReloadTime=Date.now()}async loadScripts(e,t){if(p(t))for(let[e,n]of t)this.scriptMap.set(e,n);let n=Object.entries(e),r=n.map(([e])=>this.scriptMap.get(e)).filter(p),i=new Map;if(r.length>0&&p(this.cacheClient?.scriptExists)){let e=await this.cacheClient.scriptExists(r);if(p(e)){r.forEach((t,n)=>{i.set(t,e[n]??!1)});let t=e.filter(Boolean).length;t>0&&this.logger?.info({message:`${t}/${r.length} scripts already exist in Redis; skipping load for existing scripts`,category:this.name})}}for(let[e,t]of n){let n=this.scriptMap.get(e);if(n&&i.get(n))continue;let r=await this.cacheClient?.loadScript?.(t);p(r)?this.scriptMap?.set(e,r):this.logger?.error({message:`Error loading script ${e}`,category:this.name,code:te.ScriptManagerLoadingError})}}async executeScript(e,t,n){if(!this.isRedisReady())return this.logger?.warning({message:`Redis not ready, cannot execute script ${e}`,category:this.name,context:{keys:t,args:n}}),null;let i=this.scriptMap?.get(e);if(l(i))throw this.logger?.error({message:`Script for ${e} not found in script map`,category:this.name,code:te.ScriptManagerExecutionError}),Error(`Script for ${e} not found`);try{return await this.cacheClient?.executeScript?.({sha1:i,keys:t,args:n})??null}catch(a){if(a instanceof Error&&a.message.includes(`NOSCRIPT`)){let a=Date.now()-this.lastReloadTime;if(a<ne){let t=ne-a;this.logger?.info({message:`Script ${e} not found, reload occurred ${a}ms ago. Waiting ${t}ms before reloading`,category:this.name}),await r(t)}if(this.logger?.info({message:`Script ${e} not found in Redis, reloading scripts`,category:this.name}),await this.reloadScripts(),i=this.scriptMap?.get(e),l(i))throw Error(`Script for ${e} could not be reloaded`);return await this.cacheClient?.executeScript?.({sha1:i,keys:t,args:n})??null}throw a instanceof Error&&this.logger?.error({message:`Error executing script ${e}: ${a.message}`,category:this.name,context:{keys:t,args:n},error:a,code:te.ScriptManagerExecutionError}),a}}isRedisReady(){let e=this.cacheClient?.getClient?.();if(p(this.cacheClient)&&l(e))return this.logger?.warning({message:`Cache client exists but getClient() returned null - cannot verify Redis readiness`,category:this.name}),!1;let t=e?.isReady&&e?.isOpen;return this.isReady()&&p(this.cacheClient)&&(t??!1)}},SubscriptionManager=class{constructor(e){this.options={getCacheClient:buildRedisClientInstance},this.subscriptionMap=null,this.subscriptionClient=null,this.name=`SubscriptionManager`,this.options={...this.options,...e}}async initialize(e=this.options){let{config:t,getCacheClient:n,logger:r}=e;if(this.logger=r,this.subscriptionMap=new MemoryStore({instantiator:`${e?.instantiator}(${this.name})`,evictionFrequency:e?.subscriptionTTL,staleDataThreshold:e?.staleSubscriptionsThreshold,truncateThreshold:e?.truncateThreshold,truncationPercentage:e?.truncationPercentage,typeGuard:e=>typeof e==`string`,dispose:async e=>{await this.subscriptionClient?.unsubscribe?.(e)}}),p(t))this.subscriptionClient=await n?.(t,this.logger,e?.instantiator)??null,this.logger?.info({message:`${this.name} initialized for ${e.instantiator}.`,category:this.name});else throw Error(`SubscriptionManager requires a Redis client configuration.`)}async subscribe(e,t){this.isReady()||await this.initialize(this.options);let n=await this.subscriptionMap?.getData(e),r=o(t.toString());return await this.subscriptionMap?.setData({key:e,value:r}),n===r?!0:await this.subscriptionClient?.subscribe?.(e,t)??!1}async unsubscribe(e){return this.isReady()||await this.initialize(this.options),this.subscriptionClient?.unsubscribe?.(e)??!1}isReady(){return p(this.subscriptionClient)&&p(this.subscriptionMap)}close(){this.subscriptionMap?.close(),this.subscriptionMap=null,this.subscriptionClient=null}};const re=15e3,ie=1e4;let ae=function(e){return e.QueueManagerInitializationError=`QueueManagerInitializationError`,e.QueueManagerJoinAndWaitTurnError=`QueueManagerJoinAndWaitTurnError`,e.QueueManagerLengthError=`QueueManagerLengthError`,e.QueueManagerPopError=`QueueManagerPopError`,e}({}),A=function(e){return e.rPush=`rPush`,e.lPush=`lPush`,e.lPop=`lPop`,e.llen=`llen`,e}({});var QueueManager=class extends ScriptManager{constructor(...e){super(...e),this.subscriptionManager=null,this.eventClient=null,this.name=`QueueManager`}async additionalInitialization(){if(l(this.redisClientConfig))throw Error(`Redis client configuration is required to initialize QueueManager.`);this.subscriptionManager=new SubscriptionManager({config:this.redisClientConfig,instantiator:this.name,subscriptionTTL:6e4,truncateThreshold:ie,truncationPercentage:1}),await this.subscriptionManager?.initialize(),this.eventClient=new EventClient({instantiator:this.name,timeoutResolveValue:!1},{instantiator:this.name,evictionFrequency:re,truncateThreshold:ie,truncationPercentage:1},{instantiator:this.name,evictionFrequency:re,truncateThreshold:ie,truncationPercentage:1}),this.logger?.info({category:this.name,message:`QueueManager initialized.`})}async joinAndWaitTurn(e,t,n,r,i=!0){try{let a=`${e}:${t}`;await this.subscriptionManager?.subscribe(a,async(n,r)=>{if(r.includes(a)&&r.includes(t)){let t=`${e}:${n}`;return this.eventClient?.resolveEvent(t,!0)}});let o=await this.executeScript(n?A.lPush:A.rPush,[e],[t,`60000`])===1;return(!i||!o)&&await this.eventClient?.waitForEvent(a,15e3),await this.eventClient?.deleteEvent(a),await r(e,t)}catch(n){throw n instanceof Error&&this.logger?.error({message:`Error in joinAndWaitTurn`,category:this.name,error:n,code:ae.QueueManagerJoinAndWaitTurnError,context:{queueName:e,value:t}}),n}}async pop(e){try{return await this.executeScript(A.lPop,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in pop`,category:this.name,error:t,code:ae.QueueManagerPopError,context:{queueName:e}}),t}}async length(e){try{return await this.executeScript(A.llen,[e],[])}catch(t){throw t instanceof Error&&this.logger?.error({message:`Error in length`,category:this.name,error:t,code:ae.QueueManagerLengthError,context:{queueName:e}}),t}}isReady(){return p(this.subscriptionManager)&&p(this.cacheClient)&&p(this.scriptMap)&&this.scriptMap.size>0}close(){this.subscriptionManager?.close(),this.scriptMap?.clear()}};const j=`__keyevent@0__:`,oe=`${j}set`,se=`${j}expire`,M=`${j}expired`,ce=`${j}srem`,le=[oe,se,M],ue={mainMaxConcurrency:30};let N=function(e){return e.ConcurrencyManagerInitializationError=`ConcurrencyManagerInitializationError`,e.ConcurrencyManagerRedisEventsEmitError=`ConcurrencyManagerRedisEventsEmitError`,e.ConcurrencyManagerRegistrationFailed=`ConcurrencyManagerRegistrationFailed`,e.ConcurrencyManagerPublishNextItemFailed=`ConcurrencyManagerPublishNextItemFailed`,e.ConcurrencyManagerReleaseRequestFailed=`ConcurrencyManagerReleaseRequestFailed`,e}({}),P=function(e){return e.tryConcurrency=`tryConcurrency`,e.removeFromSet=`removeFromSet`,e.publishNextItem=`publishNextItem`,e}({});const de={[P.tryConcurrency]:`
2
2
  local requestId = KEYS[1]
3
3
  local targetKey = KEYS[2]
4
4
  local queueKey = KEYS[3]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackone/transport",
3
- "version": "2.17.0",
3
+ "version": "2.18.0",
4
4
  "description": "",
5
5
  "main": "dist/index.cjs",
6
6
  "module": "dist/index.mjs",