@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 +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
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]
|