@bitblit/ratchet-rdbms 4.0.372-alpha → 4.0.374-alpha

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/lib/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import n from"mysql2/promise";import{Logger as t,ErrorRatchet as e,StringRatchet as i,RequireRatchet as r,PromiseRatchet as s,StopWatch as o,TimeoutToken as a,DurationRatchet as A}from"@bitblit/ratchet-common";import c from"get-port";import*as l from"tunnel-ssh";class u{constructor(){}static buildInformation(){return{version:"372",hash:"85b22589f5d38cdcb9c03b0febd589e9fd8656a3",branch:"alpha-2024-06-20-2",tag:"alpha-2024-06-20-2",timeBuiltISO:"2024-06-20T22:31:14-0700",notes:"No notes"}}}var E,g;!function(n){n.Asc="Asc",n.Desc="Desc"}(E||(E={})),function(n){n.Default="Default",n.ReadUncommitted="READ UNCOMMITTED"}(g||(g={}));class B{_connection;_connectionOptions;constructor(n,t){this._connection=n,this._connectionOptions=t}getRawDatabase(){return this._connection}getRawDatabaseConfig(){return this._connectionOptions}async close(){return Promise.resolve(!1)}escape(n){return this._connection.escape(n)}async preQuery(){this._connection.config.namedPlaceholders=!0}async query(n,t){const[e,i]=await this._connection.query(n,t);return{results:e,fields:i}}async onQuerySuccessOrFailure(){this._connection.config.namedPlaceholders=!1}}class M{configPromiseProvider;additionalConfig;ssh;static DEFAULT_CONNECTION_OPTIONS={multipleStatements:!0};connectionCache=new Map;cacheConfigPromise;constructor(n,e=M.DEFAULT_CONNECTION_OPTIONS,i){this.configPromiseProvider=n,this.additionalConfig=e,this.ssh=i,this.cacheConfigPromise=this.createConnectionConfig(),t.info("Added shutdown handler to the process (Only once per instantiation)"),this.addShutdownHandlerToProcess()}get usingSshTunnel(){return!!this.ssh}addShutdownHandlerToProcess(){process.on("exit",(()=>{t.info("Process is shutting down, closing connections"),this.clearDatabaseAccessCache().catch((n=>{t.error("Shutdown connection failed : %s",n)}))}))}async clearDatabaseAccessCache(){t.info("Clearing connection cache for RdsMysqlConnectionProvider");const n=Array.from(this.connectionCache.values());if(this.cacheConfigPromise=null,this.connectionCache=new Map,n.length>0)for(let i=0;i<n.length;i++){t.info("Shutting down old connection %d of %d",i,n.length);try{const r=await n[i];if(t.info("Conn %d is %s",i,r?.config?.label),r.db){t.info("Stopping connection to database");try{r.db.destroy(),t.info("Database connection closed")}catch(n){e.asErr(n).message.includes("closed state")||t.error("Something went wrong closing the database connection : %s",n)}}if(r.ssh)try{t.info("Stopping ssh tunnel"),await this.ssh.shutdown(r.ssh),t.info("Ssh tunnel stopped")}catch(n){t.warn("Failed to stop ssh tunnel : %s",n,n)}}catch(n){t.warn("Shutdown failed : %s ",n,n)}}return t.info("Old db and tunnels removed"),!1}async getConnectionAndTunnel(n){if(t.silly("getConnectionAndTunnel : %s",n),!this.connectionCache.has(n)){t.info("No connectionCache found for %s - creating new one",n);const e=await this.getDbConfig(n),i=this.createConnectionAndTunnel(e,this.additionalConfig,!0);this.connectionCache.set(n,i),t.info("Added connectionCache for %s",n)}return this.connectionCache.get(n)}async getDatabaseAccess(n){t.silly("getConnection : %s",n);const e=await this.getConnectionAndTunnel(n);return e?.db?new B(e.db,this.additionalConfig):null}async createNonPooledConnectionAndTunnel(n,e=M.DEFAULT_CONNECTION_OPTIONS){t.info("Creating non-pooled connection for %s",n.databaseName);const i=await this.getDbConfig(n.databaseName);return await this.createConnectionAndTunnel(i,e,!1)}async createNonPooledDatabaseConnection(n,t=M.DEFAULT_CONNECTION_OPTIONS){const e=await this.createNonPooledConnectionAndTunnel(n,t);return e?.db}async getDbConfig(n){t.info("RdsMysqlStyleConnectionProvider:getDbConfig:Initiating promise for %s",n);const r=await this.configPromise(),s=i.trimToEmpty(n).toLowerCase(),o=r.dbList.find((n=>i.trimToEmpty(n.label).toLowerCase()===s));if(!o)throw e.fErr("Cannot find any connection config named %s (Available are %j)",n,r.dbList.map((n=>n.label)));return o}async createConnectionAndTunnel(e,i=M.DEFAULT_CONNECTION_OPTIONS,s){t.info("In RdsMysqlStyleConnectionProvider:createConnectionAndTunnel : %s",e.label),r.notNullOrUndefined(e,"dbCfg");let o,a=null;if(e.sshTunnelConfig){const n=e.sshTunnelConfig.forceLocalPort||await c();t.debug("SSH tunnel config found, opening tunnel to %s / %s to using local port %s",e.sshTunnelConfig.host,e.sshTunnelConfig.port,n),a=await this.ssh.createSSHTunnel(e.sshTunnelConfig,e.host,e.port,n),t.debug("SSH Tunnel open")}else t.debug("No ssh configuration - skipping tunnel");t.debug("Opening connection for RdsMysqlStyleConnectionProvider");try{const t=structuredClone(e);delete t.label,delete t.sshTunnelConfig,a&&(t.host="localhost",t.port=a.localPort),o=await n.createConnection({...i,...t})}catch(n){return t.info("Failed trying to create connection : %s : clearing for retry",n),void(s&&(this.connectionCache=new Map))}o.on("error",(n=>{t.info("An error was detected on the connection : %s : Clearing",n),this.clearDatabaseAccessCache().then((n=>{t.info("Connection cleared: %s",n)})).catch((n=>t.error("Failed to clear RDS connection cache: %j",n)))})),t.info("Added error handler to db, there are now %d error handlers and %d shutdown handlers",o.rawListeners("error").length,process.rawListeners("exit").length);return{config:e,db:o,ssh:a}}configPromise(){return this.cacheConfigPromise||(this.cacheConfigPromise=this.createConnectionConfig()),this.cacheConfigPromise}async createConnectionConfig(){r.notNullOrUndefined(this.configPromiseProvider,"input");const n=this.configPromiseProvider();t.info("Creating connection config");const i=await n;return r.true(i.dbList.length>0,"input.dbList"),i.dbList.forEach((n=>{const t=M.validDbConfig(n);if(t?.length)throw e.fErr("Errors found in db config : %j",t)})),i}static validDbConfig(n){let t=[];return n?(t.push(i.trimToNull(n.host)?null:"host is required and non-empty"),t.push(i.trimToNull(n.label)?null:"label is required and non-empty"),t.push(i.trimToNull(n.database)?null:"database is required and non-empty"),t.push(i.trimToNull(n.user)?null:"user is required and non-empty"),t.push(i.trimToNull(n.password)?null:"password is required and non-empty"),t.push(n.port?null:"port is required and non-empty")):t.push("The config is null"),n.sshTunnelConfig&&(t.push(i.trimToNull(n.sshTunnelConfig.host)?null:"If sshTunnelConfig is non-null, host is required and non-empty"),t.push(n.sshTunnelConfig.port?null:"If sshTunnelConfig is non-null, port is required and non-empty")),t=t.filter((n=>!!n)),t}}class w{query;namedParams;paginator;transactionIsolationLevel;constructor(n,t,e,i){this.query=n,this.namedParams=t,this.paginator=e,this.transactionIsolationLevel=i}}class h{static ALLOWED_SQL_CONSTRUCT=/^[a-z0-9_.`]+$/i;queryProvider;query;meta=Object.freeze({});sqlConstructs={};namedParams={};conditionals={};debugComment="";paginator;debugAnnotateMode=!1;transactionIsolationLevel=g.Default;constructor(n){this.queryProvider=n}clone(){const n=new h(this.queryProvider);return this.query&&n.withBaseQuery(this.query),n.sqlConstructs=structuredClone(this.sqlConstructs),n.namedParams=structuredClone(this.namedParams),n.conditionals=structuredClone(this.conditionals),n.paginator=structuredClone(this.paginator),n.debugComment=this.debugComment,n.transactionIsolationLevel=this.transactionIsolationLevel,n}withTransactionIsolationLevel(n){return this.transactionIsolationLevel=n,this}withDebugComment(n){return this.debugComment=n,this}appendDebugComment(n){return this.debugComment=this.debugComment+n,this}withNamedQuery(n){return this.query=this.queryProvider.fetchQuery(n),i.trimToNull(this.query)||e.throwFormattedErr("Requested query that does not exist : %s",n),this.meta=Object.freeze({queryPath:n}),this.withDebugComment(" "+n+" "),this}withBaseQuery(n){this.query=n}withSqlConstruct(n,t){return this.sqlConstructs[n]=t,this}withSqlConstructs(n){return this.sqlConstructs=Object.assign(this.sqlConstructs,n),this}removeParam(n){return delete this.namedParams[n],this}paramNames(){return Object.keys(this.namedParams)}withParam(n,t){return this.namedParams[n]=t,this}withParams(n){return this.namedParams=Object.assign(this.namedParams,n),this}withExpandedParam(n,e,i){const r=n+"Length";let s=this.fetchCopyOfParam(r)??0;if(s>0&&!i){t.silly("Old item found and not extending - removing old params");this.paramNames().filter((t=>t.startsWith(n))).forEach((n=>this.removeParam(n))),s=0}this.withParam(r,e.length+s);for(let t=0;t<e.length;t++){const i=e[t];if("object"==typeof i&&i)for(const e of Object.keys(i)){const r=n+e.charAt(0).toUpperCase()+e.slice(1)+(t+s);this.withParam(r,i[e])}else{const e=n+t;this.withParam(e,i)}}return this}withConditional(n,t=!0){return this.conditionals[n]=t,this}withConditionals(n){return this.conditionals=Object.assign(this.conditionals,n),this}withPaginator(n){return r.notNullOrUndefined(n,"paginator"),r.notNullOrUndefined(n.cn,"paginator.cn"),r.true(n.min||n.max||n.l,"paginator must have some limit"),n.s=n.s??E.Asc,this.paginator=n,this}fetchCopyOfParam(n){return this.namedParams[n]}fetchCopyOfConditional(n){return this.conditionals[n]}containsParam(n){return null!=this.namedParams[n]}getDebugComment(){return this.debugComment}containsConditional(n){return null!=this.conditionals[n]}build(){return this.clone().internalBuild(!1)}buildUnfiltered(){return this.clone().internalBuild(!0)}internalBuild(n){return this.applyQueryFragments(),this.applyConditionalBlocks(),this.applyRepeatBlocks(),this.applyPagination(n),this.applySqlConstructs(),this.applyComments(),this.runQueryChecks(),this.stripNonAsciiParams(),new w((this.query??"").trim(),this.namedParams,this.paginator,this.transactionIsolationLevel)}stripNonAsciiParams(){const n=i.stripNonAscii(JSON.stringify(this.namedParams));this.namedParams=JSON.parse(n)}runQueryChecks(){const n=[...this.query?.matchAll(/['"]:[A-z-]*['"]/gm)??[]];n.length>0&&t.warn("The resulting query contains quoted named params check this this is intended. Instances found: %s",n.join(", "))}applyComments(){if(this.debugComment.length&&this.query){const n=this.query.indexOf(" "),t=this.debugComment;this.query=this.query.substring(0,n+1)+`/*${t}*/`+this.query.substring(n+1)}}applySqlConstructs(){for(const n of Object.keys(this.sqlConstructs)){let t;const e=this.sqlConstructs[n];if(Array.isArray(e))e.forEach((n=>{if("string"!=typeof n||!n.match(h.ALLOWED_SQL_CONSTRUCT))throw new Error(`sql construct entry ${n} is invalid value must be alphanumeric only.`)})),t=e.join(", ");else if(t=i.safeString(e),t.length>0&&!t.match(h.ALLOWED_SQL_CONSTRUCT))throw new Error(`sql construct ${t} is invalid value must be alphanumeric only.`);const r=["update","insert","delete","drop","select"];for(const n of r)if(t.toLowerCase().includes(n))throw new Error(`sql construct ${t} is invalid value must not contain reserved word ${n}.`);const s=`##sqlConstruct:${n}##`;for(;this.query?.includes(s);)this.query=this.query.replace(s,t)}}applyRepeatBlocks(){const n="<repeat";for(;;){const t=this.query?.indexOf(n);if(-1===t||!this.query||"number"!=typeof t)return;const e=this.query.indexOf(">",t);if(-1==e)throw new Error(`Invalid query when finding end symbol matching > in ${this.query} check that you have closed all your tags correctly.`);const i="count=";let r="";const s="join=";let o;const a=this.query.substring(t+7,e).trim().split(" ");for(const n of a)n.includes(i)&&(r=n.substring(n.indexOf(i)+i.length)),n.includes(s)&&(o=n.substring(n.indexOf(s)+s.length));const A="</repeat>",c=this.query.indexOf(A),l=this.query.substring(e+1,c);this.query=this.query.substring(0,t)+this.query.substring(c+A.length);const u=this.namedParams[r.substring(1)];for(let n=0;n<u;n++){let e=l;o&&0!=n&&(e+=o);let i=e.indexOf("::");for(;-1!=i;){const t=e.indexOf("::",i+2);if(-1==t)throw new Error(`Invalid query when finding end symbol matching :: check that you have closed all your tags correctly. Query: ${this.query} `);const r=e.substring(i+2,t);e=e.replace("::"+r+"::",":"+r+n),i=e.indexOf("::")}this.query=this.query.substring(0,t)+e+this.query.substring(t)}}}applyQueryFragments(){for(;;){const n=this.query?.indexOf("[[");if(-1==n||!this.query||"number"!=typeof n)return;const t=this.query.indexOf("]]",n);if(-1==t)throw new Error(`Invalid query when finding end symbol matching ]] in ${this.query} check that you have closed all your tags correctly.`);const e=this.query.substring(n+2,t),i=this.queryProvider.fetchQuery(e);if(!i)throw new Error(`Invalid query, query fragment ${e} not found in named queries.`);this.query=this.query.replace(`[[${e}]]`,i)}}applyPagination(n){const t="##pagination##";if(!n&&this.paginator){const n=this.paginator.s==E.Desc?E.Desc:E.Asc,t=i.safeString(n);if(this.paginator.min||this.paginator.max){let n="WHERE ##sqlConstruct:queryBuilderPaginatorWhere##";this.withSqlConstruct("queryBuilderPaginatorWhere",this.paginator.cn),this.paginator.min&&(n+=">= :queryBuilderPaginatorWhereMin",this.withParam("queryBuilderPaginatorWhereMin",this.paginator.min)),this.paginator.max&&(this.paginator.min&&(n+=" AND ##sqlConstruct:queryBuilderPaginatorWhere##"),n+="< :queryBuilderPaginatorWhereMax",this.withParam("queryBuilderPaginatorWhereMax",this.paginator.max)),this.query+=n}this.query+=` ORDER BY ##sqlConstruct:queryBuilderOrderBy## ${t}`,this.withSqlConstruct("queryBuilderOrderBy",this.paginator.cn),this.paginator.l&&(this.query+=" LIMIT :queryBuilderLimit",this.withParam("queryBuilderLimit",this.paginator.l))}if(n&&this.query){const n=this.query.indexOf(t);-1!=n&&(this.query="SELECT COUNT(*) "+this.query.substring(n+14))}for(;this.query?.includes(t);)this.query=this.query.replace(t,"")}applyConditionalBlocks(){const n=">>";for(;;){const t=this.query?.indexOf("<<");if(-1==t||!this.query||"number"!=typeof t)return;const e=this.query.indexOf(n,t);if(-1==e)throw new Error(`Invalid query when finding end symbol matching ${n} in ${this.query} check that you have closed all your tags correctly.`);const i=this.query.substring(t+2,e),r=i.replace(":",""),s=`<</${i}>>`,o=this.query.indexOf(s);if(-1==o)throw new Error(`Invalid query when finding conditional end tag matching ${s} in ${this.query} check that your query contains an exact match of this tag.`);let a=this.query.substring(e+2,o);if(i.startsWith(":")){const n=this.namedParams[r];(null==n||Array.isArray(n)&&0==n.length)&&(a="")}else{const n=this.conditionals[r.replace("!","")];null!=n&&n!=r.startsWith("!")||(a="")}this.debugAnnotateMode&&(a="/* conditional "+r+"*/"),this.query=this.query.substring(0,t)+a+this.query.substring(o+s.length)}}}class d{fields=[];replacements={};addReplacement(n,...t){this.replacements=Object.assign(this.replacements,n),this.addFields(...t)}appendReplacement(n,t,...e){this.replacements[n]=this.replacements[n]+t,this.addFields(...e)}addFields(...n){this.fields=this.fields.concat(...n)}getFields(){return this.fields}getReplacements(){return this.replacements}static sqlInjectionUnsafeParamRenderer(n){const t=n=>"string"==typeof n?'"'+n+'"':i.safeString(n);return Array.isArray(n)?n.map((n=>t(n))).join(","):t(n)}static renderQueryStringForPasteIntoTool(n,t,e=d.sqlInjectionUnsafeParamRenderer){const i=t??{};let r=d.reformatQueryForLogging(n);if(r){const n=Object.keys(i);n.sort(((n,t)=>t.length-n.length));for(const t of n){const n=":"+t,s=e(i[t]);r=r.split(n).join(s)}r.endsWith(";")||(r+=";")}return r}static reformatQueryForLogging(n,e=80){let r=e;if(!i.trimToNull(n))return null;let s="",o=i.trimToEmpty(n).split("\n").join(" ").split("\r").join(" ");for(;o.length>r;){let n=Math.min(o.length,r);for(;n>0&&![" ",","].includes(o.charAt(n));)n--;n>0?(s+=o.substring(0,n)+"\n",o=i.trimToEmpty(o.substring(n))):(t.silly("Input contains a string longer than the max line length - bumping"),r+=2)}return s+(o.length>0?o:"")}}class I{queryProvider;connectionProvider;queryDefaults;static LONG_QUERY_TIME_MS=8500;serviceName="TBD";constructor(n,t,e){this.queryProvider=n,this.connectionProvider=t,this.queryDefaults=e,this.serviceName="NamedParameterDatabaseService"}nonPooledExtraConfiguration(){return null}nonPooledMode(){return!1}get databaseAccessProvider(){return this.connectionProvider}getQueryDefaults(){return this.queryDefaults}getQueryProvider(){return this.queryProvider}async createNonPooledDatabaseAccess(n,e){if(t.info("createTransactional : %s : %j",n,e),!this.connectionProvider.createNonPooledDatabaseAccess)throw new Error("Connection provider does not implement createNonPooledDatabaseAccess");const i=await this.connectionProvider.createNonPooledDatabaseAccess(n,e);if(!i)throw new Error(`Connection could not be created for DB type ${n}`);return i}fetchQueryRawTextByName(n){return this.queryProvider.fetchQuery(n)}queryBuilder(n){const t=new h(this.queryProvider);return n&&t.withNamedQuery(n),t}async executeUpdateOrInsertByName(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t??{});return this.buildAndExecuteUpdateOrInsert(i,e)}async buildAndExecuteUpdateOrInsert(n,t=this.queryDefaults.timeoutMS){const e=n.build();return(await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t)).results}async buildAndExecuteUpdateOrInsertWithRetry(n,e,i=this.queryDefaults.timeoutMS){let r,o=0;for(;!r&&o<e;){o++;try{r=await this.buildAndExecuteUpdateOrInsert(n,i)}catch(n){t.info("Caught problem while trying to update/insert : %d : %s ",o,n),await s.wait(2e3*o)}}if(!r)throw new Error(`Failed to execute update after ${e} retries`);return r}async executeQueryByName(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t);return await this.buildAndExecute(i,e)}async executeQueryByNameSingle(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t),r=await this.buildAndExecute(i,e);return 1===r.length?r[0]:null}async buildAndExecute(n,t=this.queryDefaults.timeoutMS){const e=n.build();return(await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t,n.getDebugComment())).results}async buildAndExecuteSingle(n,t=this.queryDefaults.timeoutMS){const e=n.build(),i=await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t,n.getDebugComment());return 1===i.results.length?i.results[0]:null}async buildAndExecuteFetchTotalRows(n,e="",i=this.queryDefaults.timeoutMS){const r=n.buildUnfiltered();let s=r.query.replace("COUNT(*)",`${e} as groupByField, COUNT(*) as count`);s=`${s} GROUP BY ${e}`,t.info("Unfiltered query %s",r.query);return(await this.executeQueryWithMeta(r.transactionIsolationLevel,s,r.namedParams,i)).results}async executeQueryWithMeta(n,e,i={},r=this.queryDefaults.timeoutMS,c){const l=new o;r||(r=this.queryDefaults.timeoutMS),await this.changeNextQueryTransactionIsolationLevel(n);const u=await s.timeout(this.innerExecutePreparedAsPromiseWithRetryCloseConnection(e,i,void 0),"Query:"+e,r);if(a.isTimeoutToken(u)){t.warn("Timed out (after %s): %j",A.colonFormatMsDuration(r),u);const n=A.colonFormatMsDuration(r);throw new Error(`Timed out (after ${n}) waiting for query : ${e}`)}const E=u;return E.results||t.error("DB:executeQueryWithMeta:Failure: %j",E),c&&l.elapsedMS()>I.LONG_QUERY_TIME_MS&&t.info("NamedParameterDatabaseService long query: %s, %s",c,l.dump()),E}async shutdown(){let n;t.info("Shutting down %s service",this.serviceName);try{n=await this.connectionProvider.clearDatabaseAccessCache()}catch(e){t.error("Failure trying to shutdown : %s",e,e),n=!1}return n}async testConnection(n=!1){n||t.info("Running connection test");const e=(await this.executeQueryWithMeta(g.Default,"SELECT UNIX_TIMESTAMP(now())*1000 AS test")).results,i=1===e.length?e[0].test:null;return n||t.info("Test returned : %j",i),i}async testDbFailure(){await this.executeQueryWithMeta(g.Default,"this is a bad query")}async changeNextQueryTransactionIsolationLevel(n){return n&&n!==g.Default?(t.debug("Setting tx to %s",n),await this.innerExecutePreparedAsPromiseWithRetryCloseConnection("SET TRANSACTION ISOLATION LEVEL "+n,{})):null}async forceCloseConnectionForTesting(){t.warn("Forcing connection closed for testing");const n=await this.getDB();try{return await n.close(),t.info("Connection has been ended, but not set to null"),!0}catch(n){return t.error("Error closing connection : %s",n,n),!1}}async innerExecutePreparedAsPromiseWithRetryCloseConnection(n,i={},r=1){try{return await this.innerExecutePreparedAsPromise(n,i)}catch(o){const a=e.asErr(o);if(a.message.includes("closed state")||a.message.includes("This socket has been ended by the other party")||a.message.includes("ETIMEDOUT")||a.message.includes("RatchetNoConnection")||a.message.includes("ER_LOCK_WAIT_TIMEOUT")){const e=Math.min(1e3*r);if(t.warn("Found closed connection or lock timeout - clearing and attempting retry after %d (try %d of 3) (%s)",e,r,a.message),r<4){const o=await this.connectionProvider.clearDatabaseAccessCache();return t.info("Clear connection cache returned %s",o),await s.wait(e),this.innerExecutePreparedAsPromiseWithRetryCloseConnection(n,i,r+1)}throw t.warn("Ran out of retries"),new Error("Connection closed and cannot retry any more - dying horribly")}t.error("Named Param DB Query Failed : Err: %s Query: %s Params: %j",a,n,i,a);try{const e=await this.getDB();t.error("-----\nFor paste into tooling only: \n\n%s\n\n",d.renderQueryStringForPasteIntoTool(n,i,(n=>e.escape(n))))}catch(n){t.error("Really bad - failed trying to get the conn for logging : %s",n)}throw a}}async innerExecutePreparedAsPromise(n,e={}){const i=await this.getDB();i.preQuery&&await i.preQuery();const r=new o;try{const s=await i.query(n,e);return t.debug("Success : Finished query : %s\n%s\n\nParams : %j",r.dump(),d.reformatQueryForLogging(n),e),t.debug("-----\nFor paste into tooling only : \n\n%s\n\n",d.renderQueryStringForPasteIntoTool(n,e,(n=>i.escape(n)))),i.onQuerySuccessOnly&&await i.onQuerySuccessOnly(),s}catch(n){throw i.onQueryFailureOnly&&await i.onQueryFailureOnly(),n}finally{i.onQuerySuccessOrFailure&&await i.onQuerySuccessOrFailure()}}async getDB(){const n=this.nonPooledMode()?await this.connectionProvider.createNonPooledDatabaseAccess(this.queryDefaults,this.nonPooledExtraConfiguration()):await this.connectionProvider.getDatabaseAccess(this.queryDefaults.databaseName);if(!n)throw new Error("RatchetNoConnection : getConnection returned null - likely failed to get connection from db");return n}async resetConnection(){let n=!1;t.info("Resetting connection");try{await this.connectionProvider.clearDatabaseAccessCache();n=!!await this.testConnection(),t.info("Reset connection returning %s",n)}catch(n){t.error("Failed to reset connection : %s",n)}return n}}class C{async shutdown(n){if(!n.connection)return t.info("Not shutting down tunnel - non-tunnel passed"),!1;try{return t.info("Shutting down SSH Tunnel"),n.connection.end(),n.server.close(),!0}catch(n){return t.error("Error closing ssh tunnel : %s",n),!1}}async createSSHTunnel(n,e,i,r){const s={autoClose:!0},o={port:r},a={srcAddr:"localhost",srcPort:r,dstAddr:e,dstPort:i},[A,c]=await l.createTunnel(s,o,n,a);A.on("error",(n=>{t.warn("SSH Server Error : %s",n)}));return{localPort:r,tunnelOptions:s,serverOptions:o,sshOptions:n,forwardOptions:a,server:A,connection:c}}}class Q extends I{myQueryProvider;myConnectionProvider;myQueryDefaults;additionalConfig;currentTxFlag;constructor(n,t,e,i){super(n,t,e),this.myQueryProvider=n,this.myConnectionProvider=t,this.myQueryDefaults=e,this.additionalConfig=i}nonPooledExtraConfiguration(){return this.additionalConfig}nonPooledMode(){return!0}async cleanShutdown(){t.info("cleanShutdown");try{const n=await this.myConnectionProvider.getDatabaseAccess();n&&(t.info("Shutting down connection"),await n.close())}catch(n){t.info("Failure shutting down single-use connection : %s",n)}}async startTransaction(){if(this.currentTxFlag)e.throwFormattedErr("Tried to start a new transaction while one is already in progress : %s",this.currentTxFlag);else{this.currentTxFlag=i.createRandomHexString(10),t.info("Starting a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.beginTransaction())}}async commitTransaction(){if(this.currentTxFlag){t.info("commit a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.commitTransaction()),this.currentTxFlag=void 0}else e.throwFormattedErr("Cannot commit transaction - none in process")}async rollBackTransaction(){if(this.currentTxFlag){t.info("rollBack a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.rollbackTransaction()),this.currentTxFlag=void 0}else e.throwFormattedErr("Cannot rollBack transaction - none in process")}async buildAndExecuteUpdateOrInsertInTransaction(n,e=this.myQueryDefaults.timeoutMS){t.info("buildAndExecuteUpdateOrInsertInTransaction"),await this.startTransaction();try{const t=await this.buildAndExecuteUpdateOrInsert(n,e);return await this.commitTransaction(),t}catch(n){return t.error("Failed - rolling back transaction : %s",n,n),await this.rollBackTransaction(),null}}async buildAndExecuteInTransaction(n,e=this.myQueryDefaults.timeoutMS){t.info("buildAndExecuteInTransaction"),await this.startTransaction();try{const t=await this.buildAndExecute(n,e);return await this.commitTransaction(),t}catch(n){return t.error("Failed - rolling back transaction : %s",n,n),await this.rollBackTransaction(),null}}static async oneStepBuildAndExecuteUpdateOrInsertInTransaction(n,e,i=n.getQueryDefaults().timeoutMS,r){let s,o=null;try{s=new Q(n.getQueryProvider(),n.databaseAccessProvider,n.getQueryDefaults(),r),o=await s.buildAndExecuteUpdateOrInsertInTransaction(e,i)}catch(n){t.error("Failure in oneStepBuildAndExecuteUpdateOrInsertInTransaction : %j : %s",e,n,n)}finally{s&&await s.cleanShutdown()}return o}static async oneStepBuildAndExecuteInTransaction(n,e,i=n.getQueryDefaults().timeoutMS,r){let s,o=null;try{s=new Q(n.getQueryProvider(),n.databaseAccessProvider,n.getQueryDefaults(),r),o=await s.buildAndExecuteInTransaction(e,i)}catch(n){t.error("Failure in oneStepbuildAndExecuteInTransaction : %j : %s",e,n,n)}finally{s&&await s.cleanShutdown()}return o}}class D{static US_EAST_1_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEBzCCAu+gAwIBAgICJVUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\nMRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\nDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\nMSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTkxODE2\nNTNaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\naGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\nZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\nem9uIFJEUyB1cy1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAM3i/k2u6cqbMdcISGRvh+m+L0yaSIoOXjtpNEoIftAipTUYoMhL\nInXGlQBVA4shkekxp1N7HXe1Y/iMaPEyb3n+16pf3vdjKl7kaSkIhjdUz3oVUEYt\ni8Z/XeJJ9H2aEGuiZh3kHixQcZczn8cg3dA9aeeyLSEnTkl/npzLf//669Ammyhs\nXcAo58yvT0D4E0D/EEHf2N7HRX7j/TlyWvw/39SW0usiCrHPKDLxByLojxLdHzso\nQIp/S04m+eWn6rmD+uUiRteN1hI5ncQiA3wo4G37mHnUEKo6TtTUh+sd/ku6a8HK\nglMBcgqudDI90s1OpuIAWmuWpY//8xEG2YECAwEAAaNmMGQwDgYDVR0PAQH/BAQD\nAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPqhoWZcrVY9mU7tuemR\nRBnQIj1jMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\nDQEBCwUAA4IBAQB6zOLZ+YINEs72heHIWlPZ8c6WY8MDU+Be5w1M+BK2kpcVhCUK\nPJO4nMXpgamEX8DIiaO7emsunwJzMSvavSPRnxXXTKIc0i/g1EbiDjnYX9d85DkC\nE1LaAUCmCZBVi9fIe0H2r9whIh4uLWZA41oMnJx/MOmo3XyMfQoWcqaSFlMqfZM4\n0rNoB/tdHLNuV4eIdaw2mlHxdWDtF4oH+HFm+2cVBUVC1jXKrFv/euRVtsTT+A6i\nh2XBHKxQ1Y4HgAn0jACP2QSPEmuoQEIa57bEKEcZsBR8SDY6ZdTd2HLRIApcCOSF\nMRM8CKLeF658I0XgF8D5EsYoKPsA+74Z+jDH\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/zCCAuegAwIBAgIRAPVSMfFitmM5PhmbaOFoGfUwDQYJKoZIhvcNAQELBQAw\ngZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ\nbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn\nQW1hem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH\nDAdTZWF0dGxlMCAXDTIxMDUyNTIyMzQ1N1oYDzIwNjEwNTI1MjMzNDU3WjCBlzEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6\nb24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDu9H7TBeGoDzMr\ndxN6H8COntJX4IR6dbyhnj5qMD4xl/IWvp50lt0VpmMd+z2PNZzx8RazeGC5IniV\n5nrLg0AKWRQ2A/lGGXbUrGXCSe09brMQCxWBSIYe1WZZ1iU1IJ/6Bp4D2YEHpXrW\nbPkOq5x3YPcsoitgm1Xh8ygz6vb7PsvJvPbvRMnkDg5IqEThapPjmKb8ZJWyEFEE\nQRrkCIRueB1EqQtJw0fvP4PKDlCJAKBEs/y049FoOqYpT3pRy0WKqPhWve+hScMd\n6obq8kxTFy1IHACjHc51nrGII5Bt76/MpTWhnJIJrCnq1/Uc3Qs8IVeb+sLaFC8K\nDI69Sw6bAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE7PCopt\nlyOgtXX0Y1lObBUxuKaCMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\nAQEAFj+bX8gLmMNefr5jRJfHjrL3iuZCjf7YEZgn89pS4z8408mjj9z6Q5D1H7yS\njNETVV8QaJip1qyhh5gRzRaArgGAYvi2/r0zPsy+Tgf7v1KGL5Lh8NT8iCEGGXwF\ng3Ir+Nl3e+9XUp0eyyzBIjHtjLBm6yy8rGk9p6OtFDQnKF5OxwbAgip42CD75r/q\np421maEDDvvRFR4D+99JZxgAYDBGqRRceUoe16qDzbMvlz0A9paCZFclxeftAxv6\nQlR5rItMz/XdzpBJUpYhdzM0gCzAzdQuVO5tjJxmXhkSMcDP+8Q+Uv6FA9k2VpUV\nE/O5jgpqUJJ2Hc/5rs9VkAPXeA==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\n0Ws=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAPAlEk8VJPmEzVRRaWvTh2AwCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTI1MjI0MTU1WhgPMjEyMTA1MjUyMzQxNTVaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx5xjrup8II4HOJw15NTnS3H5yMrQGlbj\nEDA5MMGnE9DmHp5dACIxmPXPMe/99nO7wNdl7G71OYPCgEvWm0FhdvVUeTb3LVnV\nBnaXt32Ek7/oxGk1T+Df03C+W0vmuJ+wo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBTGXmqBWN/1tkSea4pNw0oHrjk2UDAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIxAIqqZWCSrIkZ7zsv/FygtAusW6yvlL935YAWYPVXU30m\njkMFLM+/RJ9GMvnO8jHfCgIwB+whlkcItzE9CRQ6CsMo/d5cEHDUu/QW6jSIh9BR\nOGh9pTYPVkUbBiKPA7lVVhre\n-----END CERTIFICATE-----\n";static US_EAST_2_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIECDCCAvCgAwIBAgIDAIVCMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\nUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\nCgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\nUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTEzMTcw\nNjQxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\nc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\nU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\nYXpvbiBSRFMgdXMtZWFzdC0yIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDE+T2xYjUbxOp+pv+gRA3FO24+1zCWgXTDF1DHrh1lsPg5k7ht\n2KPYzNc+Vg4E+jgPiW0BQnA6jStX5EqVh8BU60zELlxMNvpg4KumniMCZ3krtMUC\nau1NF9rM7HBh+O+DYMBLK5eSIVt6lZosOb7bCi3V6wMLA8YqWSWqabkxwN4w0vXI\n8lu5uXXFRemHnlNf+yA/4YtN4uaAyd0ami9+klwdkZfkrDOaiy59haOeBGL8EB/c\ndbJJlguHH5CpCscs3RKtOOjEonXnKXldxarFdkMzi+aIIjQ8GyUOSAXHtQHb3gZ4\nnS6Ey0CMlwkB8vUObZU9fnjKJcL5QCQqOfwvAgMBAAGjZjBkMA4GA1UdDwEB/wQE\nAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQUPuRHohPxx4VjykmH\n6usGrLL1ETAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n9w0BAQsFAAOCAQEAUdR9Vb3y33Yj6X6KGtuthZ08SwjImVQPtknzpajNE5jOJAh8\nquvQnU9nlnMO85fVDU1Dz3lLHGJ/YG1pt1Cqq2QQ200JcWCvBRgdvH6MjHoDQpqZ\nHvQ3vLgOGqCLNQKFuet9BdpsHzsctKvCVaeBqbGpeCtt3Hh/26tgx0rorPLw90A2\nV8QSkZJjlcKkLa58N5CMM8Xz8KLWg3MZeT4DmlUXVCukqK2RGuP2L+aME8dOxqNv\nOnOz1zrL5mR2iJoDpk8+VE/eBDmJX40IJk6jBjWoxAO/RXq+vBozuF5YHN1ujE92\ntO8HItgTp37XT8bJBAiAnt5mxw+NLSqtxk2QdQ==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/zCCAuegAwIBAgIRAJYlnmkGRj4ju/2jBQsnXJYwDQYJKoZIhvcNAQELBQAw\ngZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ\nbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn\nQW1hem9uIFJEUyB1cy1lYXN0LTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH\nDAdTZWF0dGxlMCAXDTIxMDUyMTIzMDQ0NFoYDzIwNjEwNTIyMDAwNDQ0WjCBlzEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6\nb24gUkRTIHVzLWVhc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC74V3eigv+pCj5\nnqDBqplY0Jp16pTeNB06IKbzb4MOTvNde6QjsZxrE1xUmprT8LxQqN9tI3aDYEYk\nb9v4F99WtQVgCv3Y34tYKX9NwWQgwS1vQwnIR8zOFBYqsAsHEkeJuSqAB12AYUSd\nZv2RVFjiFmYJho2X30IrSLQfS/IE3KV7fCyMMm154+/K1Z2IJlcissydEAwgsUHw\nedrE6CxJVkkJ3EvIgG4ugK/suxd8eEMztaQYJwSdN8TdfT59LFuSPl7zmF3fIBdJ\n//WexcQmGabaJ7Xnx+6o2HTfkP8Zzzzaq8fvjAcvA7gyFH5EP26G2ZqMG+0y4pTx\nSPVTrQEXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIWWuNEF\nsUMOC82XlfJeqazzrkPDMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\nAQEAgClmxcJaQTGpEZmjElL8G2Zc8lGc+ylGjiNlSIw8X25/bcLRptbDA90nuP+q\nzXAMhEf0ccbdpwxG/P5a8JipmHgqQLHfpkvaXx+0CuP++3k+chAJ3Gk5XtY587jX\n+MJfrPgjFt7vmMaKmynndf+NaIJAYczjhJj6xjPWmGrjM3MlTa9XesmelMwP3jep\nbApIWAvCYVjGndbK9byyMq1nyj0TUzB8oJZQooaR3MMjHTmADuVBylWzkRMxbKPl\n4Nlsk4Ef1JvIWBCzsMt+X17nuKfEatRfp3c9tbpGlAE/DSP0W2/Lnayxr4RpE9ds\nICF35uSis/7ZlsftODUe8wtpkQ==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\nPqj2\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrDCCAjOgAwIBAgIQGcztRyV40pyMKbNeSN+vXTAKBggqhkjOPQQDAzCBljEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6\nb24gUkRTIHVzLWVhc3QtMiBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTAgFw0yMTA1MjEyMzE1NTZaGA8yMTIxMDUyMjAwMTU1NlowgZYxCzAJBgNV\nBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD\nVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE\nUyB1cy1lYXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw\ndjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQfDcv+GGRESD9wT+I5YIPRsD3L+/jsiIis\nTr7t9RSbFl+gYpO7ZbDXvNbV5UGOC5lMJo/SnqFRTC6vL06NF7qOHfig3XO8QnQz\n6T5uhhrhnX2RSY3/10d2kTyHq3ZZg3+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFLDyD3PRyNXpvKHPYYxjHXWOgfPnMA4GA1UdDwEB/wQEAwIBhjAKBggq\nhkjOPQQDAwNnADBkAjB20HQp6YL7CqYD82KaLGzgw305aUKw2aMrdkBR29J183jY\n6Ocj9+Wcif9xnRMS+7oCMAvrt03rbh4SU9BohpRUcQ2Pjkh7RoY0jDR4Xq4qzjNr\n5UFr3BXpFvACxXF51BksGQ==\n-----END CERTIFICATE-----\n";static US_WEST_1_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIECDCCAvCgAwIBAgIDAIkHMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\nUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\nCgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\nUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTA2MTc0\nMDIxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\nc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\nU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\nYXpvbiBSRFMgdXMtd2VzdC0xIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDD2yzbbAl77OofTghDMEf624OvU0eS9O+lsdO0QlbfUfWa1Kd6\n0WkgjkLZGfSRxEHMCnrv4UPBSK/Qwn6FTjkDLgemhqBtAnplN4VsoDL+BkRX4Wwq\n/dSQJE2b+0hm9w9UMVGFDEq1TMotGGTD2B71eh9HEKzKhGzqiNeGsiX4VV+LJzdH\nuM23eGisNqmd4iJV0zcAZ+Gbh2zK6fqTOCvXtm7Idccv8vZZnyk1FiWl3NR4WAgK\nAkvWTIoFU3Mt7dIXKKClVmvssG8WHCkd3Xcb4FHy/G756UZcq67gMMTX/9fOFM/v\nl5C0+CHl33Yig1vIDZd+fXV1KZD84dEJfEvHAgMBAAGjZjBkMA4GA1UdDwEB/wQE\nAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBR+ap20kO/6A7pPxo3+\nT3CfqZpQWjAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n9w0BAQsFAAOCAQEAHCJky2tPjPttlDM/RIqExupBkNrnSYnOK4kr9xJ3sl8UF2DA\nPAnYsjXp3rfcjN/k/FVOhxwzi3cXJF/2Tjj39Bm/OEfYTOJDNYtBwB0VVH4ffa/6\ntZl87jaIkrxJcreeeHqYMnIxeN0b/kliyA+a5L2Yb0VPjt9INq34QDc1v74FNZ17\n4z8nr1nzg4xsOWu0Dbjo966lm4nOYIGBRGOKEkHZRZ4mEiMgr3YLkv8gSmeitx57\nZ6dVemNtUic/LVo5Iqw4n3TBS0iF2C1Q1xT/s3h+0SXZlfOWttzSluDvoMv5PvCd\npFjNn+aXLAALoihL1MJSsxydtsLjOBro5eK0Vw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\nHing\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/jCCAuagAwIBAgIQGyUVTaVjYJvWhroVEiHPpDANBgkqhkiG9w0BAQsFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTE5MTkwNDA2WhgPMjA2MTA1MTkyMDA0MDZaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANhyXpJ0t4nigRDZ\nEwNtFOem1rM1k8k5XmziHKDvDk831p7QsX9ZOxl/BT59Pu/P+6W6SvasIyKls1sW\nFJIjFF+6xRQcpoE5L5evMgN/JXahpKGeQJPOX9UEXVW5B8yi+/dyUitFT7YK5LZA\nMqWBN/LtHVPa8UmE88RCDLiKkqiv229tmwZtWT7nlMTTCqiAHMFcryZHx0pf9VPh\nx/iPV8p2gBJnuPwcz7z1kRKNmJ8/cWaY+9w4q7AYlAMaq/rzEqDaN2XXevdpsYAK\nTMMj2kji4x1oZO50+VPNfBl5ZgJc92qz1ocF95SAwMfOUsP8AIRZkf0CILJYlgzk\n/6u6qZECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm5jfcS9o\n+LwL517HpB6hG+PmpBswDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB\nAQAcQ6lsqxi63MtpGk9XK8mCxGRLCad51+MF6gcNz6i6PAqhPOoKCoFqdj4cEQTF\nF8dCfa3pvfJhxV6RIh+t5FCk/y6bWT8Ls/fYKVo6FhHj57bcemWsw/Z0XnROdVfK\nYqbc7zvjCPmwPHEqYBhjU34NcY4UF9yPmlLOL8uO1JKXa3CAR0htIoW4Pbmo6sA4\n6P0co/clW+3zzsQ92yUCjYmRNeSbdXbPfz3K/RtFfZ8jMtriRGuO7KNxp8MqrUho\nHK8O0mlSUxGXBZMNicfo7qY8FD21GIPH9w5fp5oiAl7lqFzt3E3sCLD3IiVJmxbf\nfUwpGd1XZBBSdIxysRLM6j48\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAMkvdFnVDb0mWWFiXqnKH68wCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy13ZXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTE5MTkxMzI0WhgPMjEyMTA1MTkyMDEzMjRaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtd2VzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEy86DB+9th/0A5VcWqMSWDxIUblWTt/R0\nao6Z2l3vf2YDF2wt1A2NIOGpfQ5+WAOJO/IQmnV9LhYo+kacB8sOnXdQa6biZZkR\nIyouUfikVQAKWEJnh1Cuo5YMM4E2sUt5o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBQ8u3OnecANmG8OoT7KLWDuFzZwBTAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIwQ817qkb7mWJFnieRAN+m9W3E0FLVKaV3zC5aYJUk2fcZ\nTaUx3oLp3jPLGvY5+wgeAjEA6wAicAki4ZiDfxvAIuYiIe1OS/7H5RA++R8BH6qG\niRzUBM/FItFpnkus7u/eTkvo\n-----END CERTIFICATE-----\n";static US_WEST_2_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEBzCCAu+gAwIBAgICUYkwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\nMRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\nDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\nMSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTYxODIx\nMTVaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\naGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\nZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\nem9uIFJEUyB1cy13ZXN0LTIgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBANCEZBZyu6yJQFZBJmSUZfSZd3Ui2gitczMKC4FLr0QzkbxY+cLa\nuVONIOrPt4Rwi+3h/UdnUg917xao3S53XDf1TDMFEYp4U8EFPXqCn/GXBIWlU86P\nPvBN+gzw3nS+aco7WXb+woTouvFVkk8FGU7J532llW8o/9ydQyDIMtdIkKTuMfho\nOiNHSaNc+QXQ32TgvM9A/6q7ksUoNXGCP8hDOkSZ/YOLiI5TcdLh/aWj00ziL5bj\npvytiMZkilnc9dLY9QhRNr0vGqL0xjmWdoEXz9/OwjmCihHqJq+20MJPsvFm7D6a\n2NKybR9U+ddrjb8/iyLOjURUZnj5O+2+OPcCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\nAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEBxMBdv81xuzqcK5TVu\npHj+Aor8MB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\nDQEBCwUAA4IBAQBZkfiVqGoJjBI37aTlLOSjLcjI75L5wBrwO39q+B4cwcmpj58P\n3sivv+jhYfAGEbQnGRzjuFoyPzWnZ1DesRExX+wrmHsLLQbF2kVjLZhEJMHF9eB7\nGZlTPdTzHErcnuXkwA/OqyXMpj9aghcQFuhCNguEfnROY9sAoK2PTfnTz9NJHL+Q\nUpDLEJEUfc0GZMVWYhahc0x38ZnSY2SKacIPECQrTI0KpqZv/P+ijCEcMD9xmYEb\njL4en+XKS1uJpw5fIU5Sj0MxhdGstH6S84iAE5J3GM3XHklGSFwwqPYvuTXvANH6\nuboynxRgSae59jIlAK6Jrr6GWMwQRbgcaAlW\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAOxu0I1QuMAhIeszB3fJIlkwCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy13ZXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTI0MjIwNjU5WhgPMjEyMTA1MjQyMzA2NTlaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtd2VzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEz4bylRcGqqDWdP7gQIIoTHdBK6FNtKH1\n4SkEIXRXkYDmRvL9Bci1MuGrwuvrka5TDj4b7e+csY0llEzHpKfq6nJPFljoYYP9\nuqHFkv77nOpJJ633KOr8IxmeHW5RXgrZo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBQQikVz8wmjd9eDFRXzBIU8OseiGzAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIwf06Mcrpw1O0EBLBBrp84m37NYtOkE/0Z0O+C7D41wnXi\nEQdn6PXUVgdD23Gj82SrAjEAklhKs+liO1PtN15yeZR1Io98nFve+lLptaLakZcH\n+hfFuUtCqMbaI8CdvJlKnPqT\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIF/jCCA+agAwIBAgIQR71Z8lTO5Sj+as2jB7IWXzANBgkqhkiG9w0BAQwFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTI0MjIwMzIwWhgPMjEyMTA1MjQyMzAzMjBaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM977bHIs1WJijrS\nXQMfUOhmlJjr2v0K0UjPl52sE1TJ76H8umo1yR4T7Whkd9IwBHNGKXCJtJmMr9zp\nfB38eLTu+5ydUAXdFuZpRMKBWwPVe37AdJRKqn5beS8HQjd3JXAgGKUNNuE92iqF\nqi2fIqFMpnJXWo0FIW6s2Dl2zkORd7tH0DygcRi7lgVxCsw1BJQhFJon3y+IV8/F\nbnbUXSNSDUnDW2EhvWSD8L+t4eiXYsozhDAzhBvojpxhPH9OB7vqFYw5qxFx+G0t\nlSLX5iWi1jzzc3XyGnB6WInZDVbvnvJ4BGZ+dTRpOCvsoMIn9bz4EQTvu243c7aU\nHbS/kvnCASNt+zk7C6lbmaq0AGNztwNj85Opn2enFciWZVnnJ/4OeefUWQxD0EPp\nSjEd9Cn2IHzkBZrHCg+lWZJQBKbUVS0lLIMSsLQQ6WvR38jY7D2nxM1A93xWxwpt\nZtQnYRCVXH6zt2OwDAFePInWwxUjR5t/wu3XxPgpSfrmTi3WYtr1wFypAJ811e/P\nyBtswWUQ6BNJQvy+KnOEeGfOwmtdDFYR+GOCfvCihzrKJrxOtHIieehR5Iw3cbXG\nsm4pDzfMUVvDDz6C2M6PRlJhhClbatHCjik9hxFYEsAlqtVVK9pxaz9i8hOqSFQq\nkJSQsgWw+oM/B2CyjcSqkSQEu8RLAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w\nHQYDVR0OBBYEFPmrdxpRRgu3IcaB5BTqlprcKdTsMA4GA1UdDwEB/wQEAwIBhjAN\nBgkqhkiG9w0BAQwFAAOCAgEAVdlxWjPvVKky3kn8ZizeM4D+EsLw9dWLau2UD/ls\nzwDCFoT6euagVeCknrn+YEl7g20CRYT9iaonGoMUPuMR/cdtPL1W/Rf40PSrGf9q\nQuxavWiHLEXOQTCtCaVZMokkvjuuLNDXyZnstgECuiZECTwhexUF4oiuhyGk9o01\nQMaiz4HX4lgk0ozALUvEzaNd9gWEwD2qe+rq9cQMTVq3IArUkvTIftZUaVUMzr0O\ned1+zAsNa9nJhURJ/6anJPJjbQgb5qA1asFcp9UaMT1ku36U3gnR1T/BdgG2jX3X\nUm0UcaGNVPrH1ukInWW743pxWQb7/2sumEEMVh+jWbB18SAyLI4WIh4lkurdifzS\nIuTFp8TEx+MouISFhz/vJDWZ84tqoLVjkEcP6oDypq9lFoEzHDJv3V1CYcIgOusT\nk1jm9P7BXdTG7TYzUaTb9USb6bkqkD9EwJAOSs7DI94aE6rsSws2yAHavjAMfuMZ\nsDAZvkqS2Qg2Z2+CI6wUZn7mzkJXbZoqRjDvChDXEB1mIhzVXhiNW/CR5WKVDvlj\n9v1sdGByh2pbxcLQtVaq/5coM4ANgphoNz3pOYUPWHS+JUrIivBZ+JobjXcxr3SN\n9iDzcu5/FVVNbq7+KN/nvPMngT+gduEN5m+EBjm8GukJymFG0m6BENRA0QSDqZ7k\nzDY=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/jCCAuagAwIBAgIQRiwspKyrO0xoxDgSkqLZczANBgkqhkiG9w0BAQsFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTI0MjE1OTAwWhgPMjA2MTA1MjQyMjU5MDBaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL53Jk3GsKiu+4bx\njDfsevWbwPCNJ3H08Zp7GWhvI3Tgi39opfHYv2ku2BKFjK8N2L6RvNPSR8yplv5j\nY0tK0U+XVNl8o0ibhqRDhbTuh6KL8CFINWYzAajuxFS+CF0U6c1Q3tXLBdALxA7l\nFlXJ71QrP06W31kRe7kvgrvO7qWU3/OzUf9qYw4LSiR1/VkvvRCTqcVNw09clw/M\nJbw6FSgweN65M9j7zPbjGAXSHkXyxH1Erin2fa+B9PE4ZDgX9cp2C1DHewYJQL/g\nSepwwcudVNRN1ibKH7kpMrgPnaNIVNx5sXVsTjk6q2ZqYw3SVHegltJpLy/cZReP\nmlivF2kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUmTcQd6o1\nCuS65MjBrMwQ9JJjmBwwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB\nAQAKSDSIzl956wVddPThf2VAzI8syw9ngSwsEHZvxVGHBvu5gg618rDyguVCYX9L\n4Kw/xJrk6S3qxOS2ZDyBcOpsrBskgahDFIunzoRP3a18ARQVq55LVgfwSDQiunch\nBd05cnFGLoiLkR5rrkgYaP2ftn3gRBRaf0y0S3JXZ2XB3sMZxGxavYq9mfiEcwB0\nLMTMQ1NYzahIeG6Jm3LqRqR8HkzP/Ztq4dT2AtSLvFebbNMiWqeqT7OcYp94HTYT\nzqrtaVdUg9bwyAUCDgy0GV9RHDIdNAOInU/4LEETovrtuBU7Z1q4tcHXvN6Hd1H8\ngMb0mCG5I393qW5hFsA/diFb\n-----END CERTIFICATE-----\n"}class T{static async uploadObjectArrayToTable(n,e,i,s=!1){if(r.notNullOrUndefined(n,"db"),r.notNullOrUndefined(e,"tableName"),r.notNullOrUndefined(i,"data"),t.info("Writing %d items to %s (clear: %s)",i.length,e,s),s){t.info("Clearing table %s",e);const{results:i}=await n.executeQueryWithMeta(g.Default,"DELETE FROM "+e,{});t.info("Removed %d rows",i.affectedRows)}const o=new Set(i.flatMap((n=>Object.keys(n)))),a=Array.from(o);t.info("Found columns : %j",a);const A="INSERT INTO "+e+" ("+a.join(",")+") VALUES :multiValue",{results:c}=await n.executeQueryWithMeta(g.Default,A,{multiValue:i}),l=c.affectedRows;return t.info("Wrote %d rows",l),l!==i.length&&t.warn("Should have written %d but wrote %d",i.length,l),l}}export{D as AwsRdsCert2023,B as MysqlStyleDatabaseAccess,I as NamedParameterDatabaseService,h as QueryBuilder,w as QueryBuilderResult,d as QueryUtil,u as RatchetRdbmsInfo,M as RdsMysqlStyleConnectionProvider,T as RelationalDatabaseUtils,E as SortDirection,C as SshTunnelService,g as TransactionIsolationLevel,Q as TransactionalNamedParameterDatabaseService};
1
+ import n from"mysql2/promise";import{Logger as t,ErrorRatchet as e,StringRatchet as i,RequireRatchet as r,PromiseRatchet as s,StopWatch as o,TimeoutToken as a,DurationRatchet as A}from"@bitblit/ratchet-common";import c from"get-port";import*as l from"tunnel-ssh";class u{constructor(){}static buildInformation(){return{version:"374",hash:"879fd73f525ff7dc66889feca9818985b1b7e4bc",branch:"alpha-2024-06-21-1",tag:"alpha-2024-06-21-1",timeBuiltISO:"2024-06-21T13:43:48-0700",notes:"No notes"}}}var E,g;!function(n){n.Asc="Asc",n.Desc="Desc"}(E||(E={})),function(n){n.Default="Default",n.ReadUncommitted="READ UNCOMMITTED"}(g||(g={}));class B{_connection;_connectionOptions;constructor(n,t){this._connection=n,this._connectionOptions=t}getRawDatabase(){return this._connection}getRawDatabaseConfig(){return this._connectionOptions}async close(){return Promise.resolve(!1)}escape(n){return this._connection.escape(n)}async preQuery(){this._connection.config.namedPlaceholders=!0}async query(n,t){const[e,i]=await this._connection.query(n,t);return{results:e,fields:i}}async onQuerySuccessOrFailure(){this._connection.config.namedPlaceholders=!1}}class M{configPromiseProvider;additionalConfig;ssh;static DEFAULT_CONNECTION_OPTIONS={multipleStatements:!0};connectionCache=new Map;cacheConfigPromise;constructor(n,e=M.DEFAULT_CONNECTION_OPTIONS,i){this.configPromiseProvider=n,this.additionalConfig=e,this.ssh=i,this.cacheConfigPromise=this.createConnectionConfig(),t.info("Added shutdown handler to the process (Only once per instantiation)"),this.addShutdownHandlerToProcess()}get usingSshTunnel(){return!!this.ssh}addShutdownHandlerToProcess(){process.on("exit",(()=>{t.info("Process is shutting down, closing connections"),this.clearDatabaseAccessCache().catch((n=>{t.error("Shutdown connection failed : %s",n)}))}))}async clearDatabaseAccessCache(){t.info("Clearing connection cache for RdsMysqlConnectionProvider");const n=Array.from(this.connectionCache.values());if(this.cacheConfigPromise=null,this.connectionCache=new Map,n.length>0)for(let i=0;i<n.length;i++){t.info("Shutting down old connection %d of %d",i,n.length);try{const r=await n[i];if(t.info("Conn %d is %s",i,r?.config?.label),r.db){t.info("Stopping connection to database");try{r.db.destroy(),t.info("Database connection closed")}catch(n){e.asErr(n).message.includes("closed state")||t.error("Something went wrong closing the database connection : %s",n)}}if(r.ssh)try{t.info("Stopping ssh tunnel"),await this.ssh.shutdown(r.ssh),t.info("Ssh tunnel stopped")}catch(n){t.warn("Failed to stop ssh tunnel : %s",n,n)}}catch(n){t.warn("Shutdown failed : %s ",n,n)}}return t.info("Old db and tunnels removed"),!1}async getConnectionAndTunnel(n){if(t.silly("getConnectionAndTunnel : %s",n),!this.connectionCache.has(n)){t.info("No connectionCache found for %s - creating new one",n);const e=await this.getDbConfig(n),i=this.createConnectionAndTunnel(e,this.additionalConfig,!0);this.connectionCache.set(n,i),t.info("Added connectionCache for %s",n)}return this.connectionCache.get(n)}async getDatabaseAccess(n){t.silly("getConnection : %s",n);const e=await this.getConnectionAndTunnel(n);return e?.db?new B(e.db,this.additionalConfig):null}async createNonPooledConnectionAndTunnel(n,e=M.DEFAULT_CONNECTION_OPTIONS){t.info("Creating non-pooled connection for %s",n.databaseName);const i=await this.getDbConfig(n.databaseName);return await this.createConnectionAndTunnel(i,e,!1)}async createNonPooledDatabaseConnection(n,t=M.DEFAULT_CONNECTION_OPTIONS){const e=await this.createNonPooledConnectionAndTunnel(n,t);return e?.db}async getDbConfig(n){t.info("RdsMysqlStyleConnectionProvider:getDbConfig:Initiating promise for %s",n);const r=await this.configPromise(),s=i.trimToEmpty(n).toLowerCase(),o=r.dbList.find((n=>i.trimToEmpty(n.label).toLowerCase()===s));if(!o)throw e.fErr("Cannot find any connection config named %s (Available are %j)",n,r.dbList.map((n=>n.label)));return o}async createConnectionAndTunnel(e,i=M.DEFAULT_CONNECTION_OPTIONS,s){t.info("In RdsMysqlStyleConnectionProvider:createConnectionAndTunnel : %s",e.label),r.notNullOrUndefined(e,"dbCfg");let o,a=null;if(e.sshTunnelConfig){const n=e.sshTunnelConfig.forceLocalPort||await c();t.debug("SSH tunnel config found, opening tunnel to %s / %s to using local port %s",e.sshTunnelConfig.host,e.sshTunnelConfig.port,n),a=await this.ssh.createSSHTunnel(e.sshTunnelConfig,e.host,e.port,n),t.debug("SSH Tunnel open")}else t.debug("No ssh configuration - skipping tunnel");t.debug("Opening connection for RdsMysqlStyleConnectionProvider");try{const t=structuredClone(e);delete t.label,delete t.sshTunnelConfig,a&&(t.host="localhost",t.port=a.localPort),o=await n.createConnection({...i,...t})}catch(n){return t.info("Failed trying to create connection : %s : clearing for retry",n),void(s&&(this.connectionCache=new Map))}o.on("error",(n=>{t.info("An error was detected on the connection : %s : Clearing",n),this.clearDatabaseAccessCache().then((n=>{t.info("Connection cleared: %s",n)})).catch((n=>t.error("Failed to clear RDS connection cache: %j",n)))})),t.info("Added error handler to db, there are now %d error handlers and %d shutdown handlers",o.rawListeners("error").length,process.rawListeners("exit").length);return{config:e,db:o,ssh:a}}configPromise(){return this.cacheConfigPromise||(this.cacheConfigPromise=this.createConnectionConfig()),this.cacheConfigPromise}async createConnectionConfig(){r.notNullOrUndefined(this.configPromiseProvider,"input");const n=this.configPromiseProvider();t.info("Creating connection config");const i=await n;return r.true(i.dbList.length>0,"input.dbList"),i.dbList.forEach((n=>{const t=M.validDbConfig(n);if(t?.length)throw e.fErr("Errors found in db config : %j",t)})),i}static validDbConfig(n){let t=[];return n?(t.push(i.trimToNull(n.host)?null:"host is required and non-empty"),t.push(i.trimToNull(n.label)?null:"label is required and non-empty"),t.push(i.trimToNull(n.database)?null:"database is required and non-empty"),t.push(i.trimToNull(n.user)?null:"user is required and non-empty"),t.push(i.trimToNull(n.password)?null:"password is required and non-empty"),t.push(n.port?null:"port is required and non-empty")):t.push("The config is null"),n.sshTunnelConfig&&(t.push(i.trimToNull(n.sshTunnelConfig.host)?null:"If sshTunnelConfig is non-null, host is required and non-empty"),t.push(n.sshTunnelConfig.port?null:"If sshTunnelConfig is non-null, port is required and non-empty")),t=t.filter((n=>!!n)),t}}class w{query;namedParams;paginator;transactionIsolationLevel;constructor(n,t,e,i){this.query=n,this.namedParams=t,this.paginator=e,this.transactionIsolationLevel=i}}class h{static ALLOWED_SQL_CONSTRUCT=/^[a-z0-9_.`]+$/i;queryProvider;query;meta=Object.freeze({});sqlConstructs={};namedParams={};conditionals={};debugComment="";paginator;debugAnnotateMode=!1;transactionIsolationLevel=g.Default;constructor(n){this.queryProvider=n}clone(){const n=new h(this.queryProvider);return this.query&&n.withBaseQuery(this.query),n.sqlConstructs=structuredClone(this.sqlConstructs),n.namedParams=structuredClone(this.namedParams),n.conditionals=structuredClone(this.conditionals),n.paginator=structuredClone(this.paginator),n.debugComment=this.debugComment,n.transactionIsolationLevel=this.transactionIsolationLevel,n}withTransactionIsolationLevel(n){return this.transactionIsolationLevel=n,this}withDebugComment(n){return this.debugComment=n,this}appendDebugComment(n){return this.debugComment=this.debugComment+n,this}withNamedQuery(n){return this.query=this.queryProvider.fetchQuery(n),i.trimToNull(this.query)||e.throwFormattedErr("Requested query that does not exist : %s",n),this.meta=Object.freeze({queryPath:n}),this.withDebugComment(" "+n+" "),this}withBaseQuery(n){this.query=n}withSqlConstruct(n,t){return this.sqlConstructs[n]=t,this}withSqlConstructs(n){return this.sqlConstructs=Object.assign(this.sqlConstructs,n),this}removeParam(n){return delete this.namedParams[n],this}paramNames(){return Object.keys(this.namedParams)}withParam(n,t){return this.namedParams[n]=t,this}withParams(n){return this.namedParams=Object.assign(this.namedParams,n),this}withExpandedParam(n,e,i){const r=n+"Length";let s=this.fetchCopyOfParam(r)??0;if(s>0&&!i){t.silly("Old item found and not extending - removing old params");this.paramNames().filter((t=>t.startsWith(n))).forEach((n=>this.removeParam(n))),s=0}this.withParam(r,e.length+s);for(let t=0;t<e.length;t++){const i=e[t];if("object"==typeof i&&i)for(const e of Object.keys(i)){const r=n+e.charAt(0).toUpperCase()+e.slice(1)+(t+s);this.withParam(r,i[e])}else{const e=n+t;this.withParam(e,i)}}return this}withConditional(n,t=!0){return this.conditionals[n]=t,this}withConditionals(n){return this.conditionals=Object.assign(this.conditionals,n),this}withPaginator(n){return r.notNullOrUndefined(n,"paginator"),r.notNullOrUndefined(n.cn,"paginator.cn"),r.true(n.min||n.max||n.l,"paginator must have some limit"),n.s=n.s??E.Asc,this.paginator=n,this}fetchCopyOfParam(n){return this.namedParams[n]}fetchCopyOfConditional(n){return this.conditionals[n]}containsParam(n){return null!=this.namedParams[n]}getDebugComment(){return this.debugComment}containsConditional(n){return null!=this.conditionals[n]}build(){return this.clone().internalBuild(!1)}buildUnfiltered(){return this.clone().internalBuild(!0)}internalBuild(n){return this.applyQueryFragments(),this.applyConditionalBlocks(),this.applyRepeatBlocks(),this.applyPagination(n),this.applySqlConstructs(),this.applyComments(),this.runQueryChecks(),this.stripNonAsciiParams(),new w((this.query??"").trim(),this.namedParams,this.paginator,this.transactionIsolationLevel)}stripNonAsciiParams(){const n=i.stripNonAscii(JSON.stringify(this.namedParams));this.namedParams=JSON.parse(n)}runQueryChecks(){const n=[...this.query?.matchAll(/['"]:[A-z-]*['"]/gm)??[]];n.length>0&&t.warn("The resulting query contains quoted named params check this this is intended. Instances found: %s",n.join(", "))}applyComments(){if(this.debugComment.length&&this.query){const n=this.query.indexOf(" "),t=this.debugComment;this.query=this.query.substring(0,n+1)+`/*${t}*/`+this.query.substring(n+1)}}applySqlConstructs(){for(const n of Object.keys(this.sqlConstructs)){let t;const e=this.sqlConstructs[n];if(Array.isArray(e))e.forEach((n=>{if("string"!=typeof n||!n.match(h.ALLOWED_SQL_CONSTRUCT))throw new Error(`sql construct entry ${n} is invalid value must be alphanumeric only.`)})),t=e.join(", ");else if(t=i.safeString(e),t.length>0&&!t.match(h.ALLOWED_SQL_CONSTRUCT))throw new Error(`sql construct ${t} is invalid value must be alphanumeric only.`);const r=["update","insert","delete","drop","select"];for(const n of r)if(t.toLowerCase().includes(n))throw new Error(`sql construct ${t} is invalid value must not contain reserved word ${n}.`);const s=`##sqlConstruct:${n}##`;for(;this.query?.includes(s);)this.query=this.query.replace(s,t)}}applyRepeatBlocks(){const n="<repeat";for(;;){const t=this.query?.indexOf(n);if(-1===t||!this.query||"number"!=typeof t)return;const e=this.query.indexOf(">",t);if(-1==e)throw new Error(`Invalid query when finding end symbol matching > in ${this.query} check that you have closed all your tags correctly.`);const i="count=";let r="";const s="join=";let o;const a=this.query.substring(t+7,e).trim().split(" ");for(const n of a)n.includes(i)&&(r=n.substring(n.indexOf(i)+i.length)),n.includes(s)&&(o=n.substring(n.indexOf(s)+s.length));const A="</repeat>",c=this.query.indexOf(A),l=this.query.substring(e+1,c);this.query=this.query.substring(0,t)+this.query.substring(c+A.length);const u=this.namedParams[r.substring(1)];for(let n=0;n<u;n++){let e=l;o&&0!=n&&(e+=o);let i=e.indexOf("::");for(;-1!=i;){const t=e.indexOf("::",i+2);if(-1==t)throw new Error(`Invalid query when finding end symbol matching :: check that you have closed all your tags correctly. Query: ${this.query} `);const r=e.substring(i+2,t);e=e.replace("::"+r+"::",":"+r+n),i=e.indexOf("::")}this.query=this.query.substring(0,t)+e+this.query.substring(t)}}}applyQueryFragments(){for(;;){const n=this.query?.indexOf("[[");if(-1==n||!this.query||"number"!=typeof n)return;const t=this.query.indexOf("]]",n);if(-1==t)throw new Error(`Invalid query when finding end symbol matching ]] in ${this.query} check that you have closed all your tags correctly.`);const e=this.query.substring(n+2,t),i=this.queryProvider.fetchQuery(e);if(!i)throw new Error(`Invalid query, query fragment ${e} not found in named queries.`);this.query=this.query.replace(`[[${e}]]`,i)}}applyPagination(n){const t="##pagination##";if(!n&&this.paginator){const n=this.paginator.s==E.Desc?E.Desc:E.Asc,t=i.safeString(n);if(this.paginator.min||this.paginator.max){let n="WHERE ##sqlConstruct:queryBuilderPaginatorWhere##";this.withSqlConstruct("queryBuilderPaginatorWhere",this.paginator.cn),this.paginator.min&&(n+=">= :queryBuilderPaginatorWhereMin",this.withParam("queryBuilderPaginatorWhereMin",this.paginator.min)),this.paginator.max&&(this.paginator.min&&(n+=" AND ##sqlConstruct:queryBuilderPaginatorWhere##"),n+="< :queryBuilderPaginatorWhereMax",this.withParam("queryBuilderPaginatorWhereMax",this.paginator.max)),this.query+=n}this.query+=` ORDER BY ##sqlConstruct:queryBuilderOrderBy## ${t}`,this.withSqlConstruct("queryBuilderOrderBy",this.paginator.cn),this.paginator.l&&(this.query+=" LIMIT :queryBuilderLimit",this.withParam("queryBuilderLimit",this.paginator.l))}if(n&&this.query){const n=this.query.indexOf(t);-1!=n&&(this.query="SELECT COUNT(*) "+this.query.substring(n+14))}for(;this.query?.includes(t);)this.query=this.query.replace(t,"")}applyConditionalBlocks(){const n=">>";for(;;){const t=this.query?.indexOf("<<");if(-1==t||!this.query||"number"!=typeof t)return;const e=this.query.indexOf(n,t);if(-1==e)throw new Error(`Invalid query when finding end symbol matching ${n} in ${this.query} check that you have closed all your tags correctly.`);const i=this.query.substring(t+2,e),r=i.replace(":",""),s=`<</${i}>>`,o=this.query.indexOf(s);if(-1==o)throw new Error(`Invalid query when finding conditional end tag matching ${s} in ${this.query} check that your query contains an exact match of this tag.`);let a=this.query.substring(e+2,o);if(i.startsWith(":")){const n=this.namedParams[r];(null==n||Array.isArray(n)&&0==n.length)&&(a="")}else{const n=this.conditionals[r.replace("!","")];null!=n&&n!=r.startsWith("!")||(a="")}this.debugAnnotateMode&&(a="/* conditional "+r+"*/"),this.query=this.query.substring(0,t)+a+this.query.substring(o+s.length)}}}class d{fields=[];replacements={};addReplacement(n,...t){this.replacements=Object.assign(this.replacements,n),this.addFields(...t)}appendReplacement(n,t,...e){this.replacements[n]=this.replacements[n]+t,this.addFields(...e)}addFields(...n){this.fields=this.fields.concat(...n)}getFields(){return this.fields}getReplacements(){return this.replacements}static sqlInjectionUnsafeParamRenderer(n){const t=n=>"string"==typeof n?'"'+n+'"':i.safeString(n);return Array.isArray(n)?n.map((n=>t(n))).join(","):t(n)}static renderQueryStringForPasteIntoTool(n,t,e=d.sqlInjectionUnsafeParamRenderer){const i=t??{};let r=d.reformatQueryForLogging(n);if(r){const n=Object.keys(i);n.sort(((n,t)=>t.length-n.length));for(const t of n){const n=":"+t,s=e(i[t]);r=r.split(n).join(s)}r.endsWith(";")||(r+=";")}return r}static reformatQueryForLogging(n,e=80){let r=e;if(!i.trimToNull(n))return null;let s="",o=i.trimToEmpty(n).split("\n").join(" ").split("\r").join(" ");for(;o.length>r;){let n=Math.min(o.length,r);for(;n>0&&![" ",","].includes(o.charAt(n));)n--;n>0?(s+=o.substring(0,n)+"\n",o=i.trimToEmpty(o.substring(n))):(t.silly("Input contains a string longer than the max line length - bumping"),r+=2)}return s+(o.length>0?o:"")}}class I{queryProvider;connectionProvider;queryDefaults;static LONG_QUERY_TIME_MS=8500;serviceName="TBD";constructor(n,t,e){this.queryProvider=n,this.connectionProvider=t,this.queryDefaults=e,this.serviceName="NamedParameterDatabaseService"}nonPooledExtraConfiguration(){return null}nonPooledMode(){return!1}get databaseAccessProvider(){return this.connectionProvider}getQueryDefaults(){return this.queryDefaults}getQueryProvider(){return this.queryProvider}async createNonPooledDatabaseAccess(n,e){if(t.info("createTransactional : %s : %j",n,e),!this.connectionProvider.createNonPooledDatabaseAccess)throw new Error("Connection provider does not implement createNonPooledDatabaseAccess");const i=await this.connectionProvider.createNonPooledDatabaseAccess(n,e);if(!i)throw new Error(`Connection could not be created for DB type ${n}`);return i}fetchQueryRawTextByName(n){return this.queryProvider.fetchQuery(n)}queryBuilder(n){const t=new h(this.queryProvider);return n&&t.withNamedQuery(n),t}async executeUpdateOrInsertByName(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t??{});return this.buildAndExecuteUpdateOrInsert(i,e)}async buildAndExecuteUpdateOrInsert(n,t=this.queryDefaults.timeoutMS){const e=n.build();return(await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t)).results}async buildAndExecuteUpdateOrInsertWithRetry(n,e,i=this.queryDefaults.timeoutMS){let r,o=0;for(;!r&&o<e;){o++;try{r=await this.buildAndExecuteUpdateOrInsert(n,i)}catch(n){t.info("Caught problem while trying to update/insert : %d : %s ",o,n),await s.wait(2e3*o)}}if(!r)throw new Error(`Failed to execute update after ${e} retries`);return r}async executeQueryByName(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t);return await this.buildAndExecute(i,e)}async executeQueryByNameSingle(n,t,e=this.queryDefaults.timeoutMS){const i=this.queryBuilder(n).withParams(t),r=await this.buildAndExecute(i,e);return 1===r.length?r[0]:null}async buildAndExecute(n,t=this.queryDefaults.timeoutMS){const e=n.build();return(await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t,n.getDebugComment())).results}async buildAndExecuteSingle(n,t=this.queryDefaults.timeoutMS){const e=n.build(),i=await this.executeQueryWithMeta(e.transactionIsolationLevel,e.query,e.namedParams,t,n.getDebugComment());return 1===i.results.length?i.results[0]:null}async buildAndExecuteFetchTotalRows(n,e="",i=this.queryDefaults.timeoutMS){const r=n.buildUnfiltered();let s=r.query.replace("COUNT(*)",`${e} as groupByField, COUNT(*) as count`);s=`${s} GROUP BY ${e}`,t.info("Unfiltered query %s",r.query);return(await this.executeQueryWithMeta(r.transactionIsolationLevel,s,r.namedParams,i)).results}async executeQueryWithMeta(n,e,i={},r=this.queryDefaults.timeoutMS,c){const l=new o;r||(r=this.queryDefaults.timeoutMS),await this.changeNextQueryTransactionIsolationLevel(n);const u=await s.timeout(this.innerExecutePreparedAsPromiseWithRetryCloseConnection(e,i,void 0),"Query:"+e,r);if(a.isTimeoutToken(u)){t.warn("Timed out (after %s): %j",A.colonFormatMsDuration(r),u);const n=A.colonFormatMsDuration(r);throw new Error(`Timed out (after ${n}) waiting for query : ${e}`)}const E=u;return E.results||t.error("DB:executeQueryWithMeta:Failure: %j",E),c&&l.elapsedMS()>I.LONG_QUERY_TIME_MS&&t.info("NamedParameterDatabaseService long query: %s, %s",c,l.dump()),E}async shutdown(){let n;t.info("Shutting down %s service",this.serviceName);try{n=await this.connectionProvider.clearDatabaseAccessCache()}catch(e){t.error("Failure trying to shutdown : %s",e,e),n=!1}return n}async testConnection(n=!1){n||t.info("Running connection test");const e=(await this.executeQueryWithMeta(g.Default,"SELECT UNIX_TIMESTAMP(now())*1000 AS test")).results,i=1===e.length?e[0].test:null;return n||t.info("Test returned : %j",i),i}async testDbFailure(){await this.executeQueryWithMeta(g.Default,"this is a bad query")}async changeNextQueryTransactionIsolationLevel(n){return n&&n!==g.Default?(t.debug("Setting tx to %s",n),await this.innerExecutePreparedAsPromiseWithRetryCloseConnection("SET TRANSACTION ISOLATION LEVEL "+n,{})):null}async forceCloseConnectionForTesting(){t.warn("Forcing connection closed for testing");const n=await this.getDB();try{return await n.close(),t.info("Connection has been ended, but not set to null"),!0}catch(n){return t.error("Error closing connection : %s",n,n),!1}}async innerExecutePreparedAsPromiseWithRetryCloseConnection(n,i={},r=1){try{return await this.innerExecutePreparedAsPromise(n,i)}catch(o){const a=e.asErr(o);if(a.message.includes("closed state")||a.message.includes("This socket has been ended by the other party")||a.message.includes("ETIMEDOUT")||a.message.includes("RatchetNoConnection")||a.message.includes("ER_LOCK_WAIT_TIMEOUT")){const e=Math.min(1e3*r);if(t.warn("Found closed connection or lock timeout - clearing and attempting retry after %d (try %d of 3) (%s)",e,r,a.message),r<4){const o=await this.connectionProvider.clearDatabaseAccessCache();return t.info("Clear connection cache returned %s",o),await s.wait(e),this.innerExecutePreparedAsPromiseWithRetryCloseConnection(n,i,r+1)}throw t.warn("Ran out of retries"),new Error("Connection closed and cannot retry any more - dying horribly")}t.error("Named Param DB Query Failed : Err: %s Query: %s Params: %j",a,n,i,a);try{const e=await this.getDB();t.error("-----\nFor paste into tooling only: \n\n%s\n\n",d.renderQueryStringForPasteIntoTool(n,i,(n=>e.escape(n))))}catch(n){t.error("Really bad - failed trying to get the conn for logging : %s",n)}throw a}}async innerExecutePreparedAsPromise(n,e={}){const i=await this.getDB();i.preQuery&&await i.preQuery();const r=new o;try{const s=await i.query(n,e);return t.debug("Success : Finished query : %s\n%s\n\nParams : %j",r.dump(),d.reformatQueryForLogging(n),e),t.debug("-----\nFor paste into tooling only : \n\n%s\n\n",d.renderQueryStringForPasteIntoTool(n,e,(n=>i.escape(n)))),i.onQuerySuccessOnly&&await i.onQuerySuccessOnly(),s}catch(n){throw i.onQueryFailureOnly&&await i.onQueryFailureOnly(),n}finally{i.onQuerySuccessOrFailure&&await i.onQuerySuccessOrFailure()}}async getDB(){const n=this.nonPooledMode()?await this.connectionProvider.createNonPooledDatabaseAccess(this.queryDefaults,this.nonPooledExtraConfiguration()):await this.connectionProvider.getDatabaseAccess(this.queryDefaults.databaseName);if(!n)throw new Error("RatchetNoConnection : getConnection returned null - likely failed to get connection from db");return n}async resetConnection(){let n=!1;t.info("Resetting connection");try{await this.connectionProvider.clearDatabaseAccessCache();n=!!await this.testConnection(),t.info("Reset connection returning %s",n)}catch(n){t.error("Failed to reset connection : %s",n)}return n}}class C{async shutdown(n){if(!n.connection)return t.info("Not shutting down tunnel - non-tunnel passed"),!1;try{return t.info("Shutting down SSH Tunnel"),n.connection.end(),n.server.close(),!0}catch(n){return t.error("Error closing ssh tunnel : %s",n),!1}}async createSSHTunnel(n,e,i,r){const s={autoClose:!0},o={port:r},a={srcAddr:"localhost",srcPort:r,dstAddr:e,dstPort:i},[A,c]=await l.createTunnel(s,o,n,a);A.on("error",(n=>{t.warn("SSH Server Error : %s",n)}));return{localPort:r,tunnelOptions:s,serverOptions:o,sshOptions:n,forwardOptions:a,server:A,connection:c}}}class Q extends I{myQueryProvider;myConnectionProvider;myQueryDefaults;additionalConfig;currentTxFlag;constructor(n,t,e,i){super(n,t,e),this.myQueryProvider=n,this.myConnectionProvider=t,this.myQueryDefaults=e,this.additionalConfig=i}nonPooledExtraConfiguration(){return this.additionalConfig}nonPooledMode(){return!0}async cleanShutdown(){t.info("cleanShutdown");try{const n=await this.myConnectionProvider.getDatabaseAccess();n&&(t.info("Shutting down connection"),await n.close())}catch(n){t.info("Failure shutting down single-use connection : %s",n)}}async startTransaction(){if(this.currentTxFlag)e.throwFormattedErr("Tried to start a new transaction while one is already in progress : %s",this.currentTxFlag);else{this.currentTxFlag=i.createRandomHexString(10),t.info("Starting a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.beginTransaction())}}async commitTransaction(){if(this.currentTxFlag){t.info("commit a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.commitTransaction()),this.currentTxFlag=void 0}else e.throwFormattedErr("Cannot commit transaction - none in process")}async rollBackTransaction(){if(this.currentTxFlag){t.info("rollBack a transaction : %s",this.currentTxFlag);const n=await this.myConnectionProvider.getDatabaseAccess();await(n?.rollbackTransaction()),this.currentTxFlag=void 0}else e.throwFormattedErr("Cannot rollBack transaction - none in process")}async buildAndExecuteUpdateOrInsertInTransaction(n,e=this.myQueryDefaults.timeoutMS){t.info("buildAndExecuteUpdateOrInsertInTransaction"),await this.startTransaction();try{const t=await this.buildAndExecuteUpdateOrInsert(n,e);return await this.commitTransaction(),t}catch(n){return t.error("Failed - rolling back transaction : %s",n,n),await this.rollBackTransaction(),null}}async buildAndExecuteInTransaction(n,e=this.myQueryDefaults.timeoutMS){t.info("buildAndExecuteInTransaction"),await this.startTransaction();try{const t=await this.buildAndExecute(n,e);return await this.commitTransaction(),t}catch(n){return t.error("Failed - rolling back transaction : %s",n,n),await this.rollBackTransaction(),null}}static async oneStepBuildAndExecuteUpdateOrInsertInTransaction(n,e,i=n.getQueryDefaults().timeoutMS,r){let s,o=null;try{s=new Q(n.getQueryProvider(),n.databaseAccessProvider,n.getQueryDefaults(),r),o=await s.buildAndExecuteUpdateOrInsertInTransaction(e,i)}catch(n){t.error("Failure in oneStepBuildAndExecuteUpdateOrInsertInTransaction : %j : %s",e,n,n)}finally{s&&await s.cleanShutdown()}return o}static async oneStepBuildAndExecuteInTransaction(n,e,i=n.getQueryDefaults().timeoutMS,r){let s,o=null;try{s=new Q(n.getQueryProvider(),n.databaseAccessProvider,n.getQueryDefaults(),r),o=await s.buildAndExecuteInTransaction(e,i)}catch(n){t.error("Failure in oneStepbuildAndExecuteInTransaction : %j : %s",e,n,n)}finally{s&&await s.cleanShutdown()}return o}}class D{static US_EAST_1_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEBzCCAu+gAwIBAgICJVUwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\nMRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\nDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\nMSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTkxODE2\nNTNaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\naGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\nZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\nem9uIFJEUyB1cy1lYXN0LTEgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBAM3i/k2u6cqbMdcISGRvh+m+L0yaSIoOXjtpNEoIftAipTUYoMhL\nInXGlQBVA4shkekxp1N7HXe1Y/iMaPEyb3n+16pf3vdjKl7kaSkIhjdUz3oVUEYt\ni8Z/XeJJ9H2aEGuiZh3kHixQcZczn8cg3dA9aeeyLSEnTkl/npzLf//669Ammyhs\nXcAo58yvT0D4E0D/EEHf2N7HRX7j/TlyWvw/39SW0usiCrHPKDLxByLojxLdHzso\nQIp/S04m+eWn6rmD+uUiRteN1hI5ncQiA3wo4G37mHnUEKo6TtTUh+sd/ku6a8HK\nglMBcgqudDI90s1OpuIAWmuWpY//8xEG2YECAwEAAaNmMGQwDgYDVR0PAQH/BAQD\nAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFPqhoWZcrVY9mU7tuemR\nRBnQIj1jMB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\nDQEBCwUAA4IBAQB6zOLZ+YINEs72heHIWlPZ8c6WY8MDU+Be5w1M+BK2kpcVhCUK\nPJO4nMXpgamEX8DIiaO7emsunwJzMSvavSPRnxXXTKIc0i/g1EbiDjnYX9d85DkC\nE1LaAUCmCZBVi9fIe0H2r9whIh4uLWZA41oMnJx/MOmo3XyMfQoWcqaSFlMqfZM4\n0rNoB/tdHLNuV4eIdaw2mlHxdWDtF4oH+HFm+2cVBUVC1jXKrFv/euRVtsTT+A6i\nh2XBHKxQ1Y4HgAn0jACP2QSPEmuoQEIa57bEKEcZsBR8SDY6ZdTd2HLRIApcCOSF\nMRM8CKLeF658I0XgF8D5EsYoKPsA+74Z+jDH\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/zCCAuegAwIBAgIRAPVSMfFitmM5PhmbaOFoGfUwDQYJKoZIhvcNAQELBQAw\ngZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ\nbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn\nQW1hem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH\nDAdTZWF0dGxlMCAXDTIxMDUyNTIyMzQ1N1oYDzIwNjEwNTI1MjMzNDU3WjCBlzEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6\nb24gUkRTIHVzLWVhc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDu9H7TBeGoDzMr\ndxN6H8COntJX4IR6dbyhnj5qMD4xl/IWvp50lt0VpmMd+z2PNZzx8RazeGC5IniV\n5nrLg0AKWRQ2A/lGGXbUrGXCSe09brMQCxWBSIYe1WZZ1iU1IJ/6Bp4D2YEHpXrW\nbPkOq5x3YPcsoitgm1Xh8ygz6vb7PsvJvPbvRMnkDg5IqEThapPjmKb8ZJWyEFEE\nQRrkCIRueB1EqQtJw0fvP4PKDlCJAKBEs/y049FoOqYpT3pRy0WKqPhWve+hScMd\n6obq8kxTFy1IHACjHc51nrGII5Bt76/MpTWhnJIJrCnq1/Uc3Qs8IVeb+sLaFC8K\nDI69Sw6bAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFE7PCopt\nlyOgtXX0Y1lObBUxuKaCMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\nAQEAFj+bX8gLmMNefr5jRJfHjrL3iuZCjf7YEZgn89pS4z8408mjj9z6Q5D1H7yS\njNETVV8QaJip1qyhh5gRzRaArgGAYvi2/r0zPsy+Tgf7v1KGL5Lh8NT8iCEGGXwF\ng3Ir+Nl3e+9XUp0eyyzBIjHtjLBm6yy8rGk9p6OtFDQnKF5OxwbAgip42CD75r/q\np421maEDDvvRFR4D+99JZxgAYDBGqRRceUoe16qDzbMvlz0A9paCZFclxeftAxv6\nQlR5rItMz/XdzpBJUpYhdzM0gCzAzdQuVO5tjJxmXhkSMcDP+8Q+Uv6FA9k2VpUV\nE/O5jgpqUJJ2Hc/5rs9VkAPXeA==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\n0Ws=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAPAlEk8VJPmEzVRRaWvTh2AwCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy1lYXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTI1MjI0MTU1WhgPMjEyMTA1MjUyMzQxNTVaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtZWFzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEx5xjrup8II4HOJw15NTnS3H5yMrQGlbj\nEDA5MMGnE9DmHp5dACIxmPXPMe/99nO7wNdl7G71OYPCgEvWm0FhdvVUeTb3LVnV\nBnaXt32Ek7/oxGk1T+Df03C+W0vmuJ+wo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBTGXmqBWN/1tkSea4pNw0oHrjk2UDAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIxAIqqZWCSrIkZ7zsv/FygtAusW6yvlL935YAWYPVXU30m\njkMFLM+/RJ9GMvnO8jHfCgIwB+whlkcItzE9CRQ6CsMo/d5cEHDUu/QW6jSIh9BR\nOGh9pTYPVkUbBiKPA7lVVhre\n-----END CERTIFICATE-----\n";static US_EAST_2_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIECDCCAvCgAwIBAgIDAIVCMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\nUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\nCgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\nUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTEzMTcw\nNjQxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\nc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\nU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\nYXpvbiBSRFMgdXMtZWFzdC0yIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDE+T2xYjUbxOp+pv+gRA3FO24+1zCWgXTDF1DHrh1lsPg5k7ht\n2KPYzNc+Vg4E+jgPiW0BQnA6jStX5EqVh8BU60zELlxMNvpg4KumniMCZ3krtMUC\nau1NF9rM7HBh+O+DYMBLK5eSIVt6lZosOb7bCi3V6wMLA8YqWSWqabkxwN4w0vXI\n8lu5uXXFRemHnlNf+yA/4YtN4uaAyd0ami9+klwdkZfkrDOaiy59haOeBGL8EB/c\ndbJJlguHH5CpCscs3RKtOOjEonXnKXldxarFdkMzi+aIIjQ8GyUOSAXHtQHb3gZ4\nnS6Ey0CMlwkB8vUObZU9fnjKJcL5QCQqOfwvAgMBAAGjZjBkMA4GA1UdDwEB/wQE\nAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBQUPuRHohPxx4VjykmH\n6usGrLL1ETAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n9w0BAQsFAAOCAQEAUdR9Vb3y33Yj6X6KGtuthZ08SwjImVQPtknzpajNE5jOJAh8\nquvQnU9nlnMO85fVDU1Dz3lLHGJ/YG1pt1Cqq2QQ200JcWCvBRgdvH6MjHoDQpqZ\nHvQ3vLgOGqCLNQKFuet9BdpsHzsctKvCVaeBqbGpeCtt3Hh/26tgx0rorPLw90A2\nV8QSkZJjlcKkLa58N5CMM8Xz8KLWg3MZeT4DmlUXVCukqK2RGuP2L+aME8dOxqNv\nOnOz1zrL5mR2iJoDpk8+VE/eBDmJX40IJk6jBjWoxAO/RXq+vBozuF5YHN1ujE92\ntO8HItgTp37XT8bJBAiAnt5mxw+NLSqtxk2QdQ==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/zCCAuegAwIBAgIRAJYlnmkGRj4ju/2jBQsnXJYwDQYJKoZIhvcNAQELBQAw\ngZcxCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJ\nbmMuMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEwMC4GA1UEAwwn\nQW1hem9uIFJEUyB1cy1lYXN0LTIgUm9vdCBDQSBSU0EyMDQ4IEcxMRAwDgYDVQQH\nDAdTZWF0dGxlMCAXDTIxMDUyMTIzMDQ0NFoYDzIwNjEwNTIyMDAwNDQ0WjCBlzEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdBbWF6\nb24gUkRTIHVzLWVhc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC74V3eigv+pCj5\nnqDBqplY0Jp16pTeNB06IKbzb4MOTvNde6QjsZxrE1xUmprT8LxQqN9tI3aDYEYk\nb9v4F99WtQVgCv3Y34tYKX9NwWQgwS1vQwnIR8zOFBYqsAsHEkeJuSqAB12AYUSd\nZv2RVFjiFmYJho2X30IrSLQfS/IE3KV7fCyMMm154+/K1Z2IJlcissydEAwgsUHw\nedrE6CxJVkkJ3EvIgG4ugK/suxd8eEMztaQYJwSdN8TdfT59LFuSPl7zmF3fIBdJ\n//WexcQmGabaJ7Xnx+6o2HTfkP8Zzzzaq8fvjAcvA7gyFH5EP26G2ZqMG+0y4pTx\nSPVTrQEXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIWWuNEF\nsUMOC82XlfJeqazzrkPDMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOC\nAQEAgClmxcJaQTGpEZmjElL8G2Zc8lGc+ylGjiNlSIw8X25/bcLRptbDA90nuP+q\nzXAMhEf0ccbdpwxG/P5a8JipmHgqQLHfpkvaXx+0CuP++3k+chAJ3Gk5XtY587jX\n+MJfrPgjFt7vmMaKmynndf+NaIJAYczjhJj6xjPWmGrjM3MlTa9XesmelMwP3jep\nbApIWAvCYVjGndbK9byyMq1nyj0TUzB8oJZQooaR3MMjHTmADuVBylWzkRMxbKPl\n4Nlsk4Ef1JvIWBCzsMt+X17nuKfEatRfp3c9tbpGlAE/DSP0W2/Lnayxr4RpE9ds\nICF35uSis/7ZlsftODUe8wtpkQ==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\nPqj2\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrDCCAjOgAwIBAgIQGcztRyV40pyMKbNeSN+vXTAKBggqhkjOPQQDAzCBljEL\nMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIEluYy4x\nEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMS8wLQYDVQQDDCZBbWF6\nb24gUkRTIHVzLWVhc3QtMiBSb290IENBIEVDQzM4NCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTAgFw0yMTA1MjEyMzE1NTZaGA8yMTIxMDUyMjAwMTU1NlowgZYxCzAJBgNV\nBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYD\nVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1hem9uIFJE\nUyB1cy1lYXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1NlYXR0bGUw\ndjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQfDcv+GGRESD9wT+I5YIPRsD3L+/jsiIis\nTr7t9RSbFl+gYpO7ZbDXvNbV5UGOC5lMJo/SnqFRTC6vL06NF7qOHfig3XO8QnQz\n6T5uhhrhnX2RSY3/10d2kTyHq3ZZg3+jQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYD\nVR0OBBYEFLDyD3PRyNXpvKHPYYxjHXWOgfPnMA4GA1UdDwEB/wQEAwIBhjAKBggq\nhkjOPQQDAwNnADBkAjB20HQp6YL7CqYD82KaLGzgw305aUKw2aMrdkBR29J183jY\n6Ocj9+Wcif9xnRMS+7oCMAvrt03rbh4SU9BohpRUcQ2Pjkh7RoY0jDR4Xq4qzjNr\n5UFr3BXpFvACxXF51BksGQ==\n-----END CERTIFICATE-----\n";static US_WEST_1_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIECDCCAvCgAwIBAgIDAIkHMA0GCSqGSIb3DQEBCwUAMIGPMQswCQYDVQQGEwJV\nUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEiMCAGA1UE\nCgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJE\nUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkwOTA2MTc0\nMDIxWhcNMjQwODIyMTcwODUwWjCBlDELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldh\nc2hpbmd0b24xEDAOBgNVBAcMB1NlYXR0bGUxIjAgBgNVBAoMGUFtYXpvbiBXZWIg\nU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxJTAjBgNVBAMMHEFt\nYXpvbiBSRFMgdXMtd2VzdC0xIDIwMTkgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB\nDwAwggEKAoIBAQDD2yzbbAl77OofTghDMEf624OvU0eS9O+lsdO0QlbfUfWa1Kd6\n0WkgjkLZGfSRxEHMCnrv4UPBSK/Qwn6FTjkDLgemhqBtAnplN4VsoDL+BkRX4Wwq\n/dSQJE2b+0hm9w9UMVGFDEq1TMotGGTD2B71eh9HEKzKhGzqiNeGsiX4VV+LJzdH\nuM23eGisNqmd4iJV0zcAZ+Gbh2zK6fqTOCvXtm7Idccv8vZZnyk1FiWl3NR4WAgK\nAkvWTIoFU3Mt7dIXKKClVmvssG8WHCkd3Xcb4FHy/G756UZcq67gMMTX/9fOFM/v\nl5C0+CHl33Yig1vIDZd+fXV1KZD84dEJfEvHAgMBAAGjZjBkMA4GA1UdDwEB/wQE\nAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEAMB0GA1UdDgQWBBR+ap20kO/6A7pPxo3+\nT3CfqZpQWjAfBgNVHSMEGDAWgBRzX2DYvMsDmPQrFzQuNlqmYP+8HzANBgkqhkiG\n9w0BAQsFAAOCAQEAHCJky2tPjPttlDM/RIqExupBkNrnSYnOK4kr9xJ3sl8UF2DA\nPAnYsjXp3rfcjN/k/FVOhxwzi3cXJF/2Tjj39Bm/OEfYTOJDNYtBwB0VVH4ffa/6\ntZl87jaIkrxJcreeeHqYMnIxeN0b/kliyA+a5L2Yb0VPjt9INq34QDc1v74FNZ17\n4z8nr1nzg4xsOWu0Dbjo966lm4nOYIGBRGOKEkHZRZ4mEiMgr3YLkv8gSmeitx57\nZ6dVemNtUic/LVo5Iqw4n3TBS0iF2C1Q1xT/s3h+0SXZlfOWttzSluDvoMv5PvCd\npFjNn+aXLAALoihL1MJSsxydtsLjOBro5eK0Vw==\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\n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\nHing\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/jCCAuagAwIBAgIQGyUVTaVjYJvWhroVEiHPpDANBgkqhkiG9w0BAQsFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMSBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTE5MTkwNDA2WhgPMjA2MTA1MTkyMDA0MDZaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0xIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANhyXpJ0t4nigRDZ\nEwNtFOem1rM1k8k5XmziHKDvDk831p7QsX9ZOxl/BT59Pu/P+6W6SvasIyKls1sW\nFJIjFF+6xRQcpoE5L5evMgN/JXahpKGeQJPOX9UEXVW5B8yi+/dyUitFT7YK5LZA\nMqWBN/LtHVPa8UmE88RCDLiKkqiv229tmwZtWT7nlMTTCqiAHMFcryZHx0pf9VPh\nx/iPV8p2gBJnuPwcz7z1kRKNmJ8/cWaY+9w4q7AYlAMaq/rzEqDaN2XXevdpsYAK\nTMMj2kji4x1oZO50+VPNfBl5ZgJc92qz1ocF95SAwMfOUsP8AIRZkf0CILJYlgzk\n/6u6qZECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm5jfcS9o\n+LwL517HpB6hG+PmpBswDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB\nAQAcQ6lsqxi63MtpGk9XK8mCxGRLCad51+MF6gcNz6i6PAqhPOoKCoFqdj4cEQTF\nF8dCfa3pvfJhxV6RIh+t5FCk/y6bWT8Ls/fYKVo6FhHj57bcemWsw/Z0XnROdVfK\nYqbc7zvjCPmwPHEqYBhjU34NcY4UF9yPmlLOL8uO1JKXa3CAR0htIoW4Pbmo6sA4\n6P0co/clW+3zzsQ92yUCjYmRNeSbdXbPfz3K/RtFfZ8jMtriRGuO7KNxp8MqrUho\nHK8O0mlSUxGXBZMNicfo7qY8FD21GIPH9w5fp5oiAl7lqFzt3E3sCLD3IiVJmxbf\nfUwpGd1XZBBSdIxysRLM6j48\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAMkvdFnVDb0mWWFiXqnKH68wCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy13ZXN0LTEgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTE5MTkxMzI0WhgPMjEyMTA1MTkyMDEzMjRaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtd2VzdC0xIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEy86DB+9th/0A5VcWqMSWDxIUblWTt/R0\nao6Z2l3vf2YDF2wt1A2NIOGpfQ5+WAOJO/IQmnV9LhYo+kacB8sOnXdQa6biZZkR\nIyouUfikVQAKWEJnh1Cuo5YMM4E2sUt5o0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBQ8u3OnecANmG8OoT7KLWDuFzZwBTAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIwQ817qkb7mWJFnieRAN+m9W3E0FLVKaV3zC5aYJUk2fcZ\nTaUx3oLp3jPLGvY5+wgeAjEA6wAicAki4ZiDfxvAIuYiIe1OS/7H5RA++R8BH6qG\niRzUBM/FItFpnkus7u/eTkvo\n-----END CERTIFICATE-----\n";static US_WEST_2_BUNDLE_PEM="-----BEGIN CERTIFICATE-----\nMIIEBjCCAu6gAwIBAgIJAMc0ZzaSUK51MA0GCSqGSIb3DQEBCwUAMIGPMQswCQYD\nVQQGEwJVUzEQMA4GA1UEBwwHU2VhdHRsZTETMBEGA1UECAwKV2FzaGluZ3RvbjEi\nMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1h\nem9uIFJEUzEgMB4GA1UEAwwXQW1hem9uIFJEUyBSb290IDIwMTkgQ0EwHhcNMTkw\nODIyMTcwODUwWhcNMjQwODIyMTcwODUwWjCBjzELMAkGA1UEBhMCVVMxEDAOBgNV\nBAcMB1NlYXR0bGUxEzARBgNVBAgMCldhc2hpbmd0b24xIjAgBgNVBAoMGUFtYXpv\nbiBXZWIgU2VydmljZXMsIEluYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxIDAeBgNV\nBAMMF0FtYXpvbiBSRFMgUm9vdCAyMDE5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC\nAQ8AMIIBCgKCAQEArXnF/E6/Qh+ku3hQTSKPMhQQlCpoWvnIthzX6MK3p5a0eXKZ\noWIjYcNNG6UwJjp4fUXl6glp53Jobn+tWNX88dNH2n8DVbppSwScVE2LpuL+94vY\n0EYE/XxN7svKea8YvlrqkUBKyxLxTjh+U/KrGOaHxz9v0l6ZNlDbuaZw3qIWdD/I\n6aNbGeRUVtpM6P+bWIoxVl/caQylQS6CEYUk+CpVyJSkopwJlzXT07tMoDL5WgX9\nO08KVgDNz9qP/IGtAcRduRcNioH3E9v981QO1zt/Gpb2f8NqAjUUCUZzOnij6mx9\nMcZ+9cWX88CRzR0vQODWuZscgI08NvM69Fn2SQIDAQABo2MwYTAOBgNVHQ8BAf8E\nBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUc19g2LzLA5j0Kxc0LjZa\npmD/vB8wHwYDVR0jBBgwFoAUc19g2LzLA5j0Kxc0LjZapmD/vB8wDQYJKoZIhvcN\nAQELBQADggEBAHAG7WTmyjzPRIM85rVj+fWHsLIvqpw6DObIjMWokpliCeMINZFV\nynfgBKsf1ExwbvJNzYFXW6dihnguDG9VMPpi2up/ctQTN8tm9nDKOy08uNZoofMc\nNUZxKCEkVKZv+IL4oHoeayt8egtv3ujJM6V14AstMQ6SwvwvA93EP/Ug2e4WAXHu\ncbI1NAbUgVDqp+DRdfvZkgYKryjTWd/0+1fS8X1bBZVWzl7eirNVnHbSH2ZDpNuY\n0SBd8dj5F6ld3t58ydZbrTHze7JJOd8ijySAp4/kiu9UfZWuTPABzDa/DSdz9Dk/\nzPW4CXXvhLmE02TA9/HeCw3KEHIwicNuEfw=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIEBzCCAu+gAwIBAgICUYkwDQYJKoZIhvcNAQELBQAwgY8xCzAJBgNVBAYTAlVT\nMRAwDgYDVQQHDAdTZWF0dGxlMRMwEQYDVQQIDApXYXNoaW5ndG9uMSIwIAYDVQQK\nDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMuMRMwEQYDVQQLDApBbWF6b24gUkRT\nMSAwHgYDVQQDDBdBbWF6b24gUkRTIFJvb3QgMjAxOSBDQTAeFw0xOTA5MTYxODIx\nMTVaFw0yNDA4MjIxNzA4NTBaMIGUMQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2Fz\naGluZ3RvbjEQMA4GA1UEBwwHU2VhdHRsZTEiMCAGA1UECgwZQW1hem9uIFdlYiBT\nZXJ2aWNlcywgSW5jLjETMBEGA1UECwwKQW1hem9uIFJEUzElMCMGA1UEAwwcQW1h\nem9uIFJEUyB1cy13ZXN0LTIgMjAxOSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEP\nADCCAQoCggEBANCEZBZyu6yJQFZBJmSUZfSZd3Ui2gitczMKC4FLr0QzkbxY+cLa\nuVONIOrPt4Rwi+3h/UdnUg917xao3S53XDf1TDMFEYp4U8EFPXqCn/GXBIWlU86P\nPvBN+gzw3nS+aco7WXb+woTouvFVkk8FGU7J532llW8o/9ydQyDIMtdIkKTuMfho\nOiNHSaNc+QXQ32TgvM9A/6q7ksUoNXGCP8hDOkSZ/YOLiI5TcdLh/aWj00ziL5bj\npvytiMZkilnc9dLY9QhRNr0vGqL0xjmWdoEXz9/OwjmCihHqJq+20MJPsvFm7D6a\n2NKybR9U+ddrjb8/iyLOjURUZnj5O+2+OPcCAwEAAaNmMGQwDgYDVR0PAQH/BAQD\nAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFEBxMBdv81xuzqcK5TVu\npHj+Aor8MB8GA1UdIwQYMBaAFHNfYNi8ywOY9CsXNC42WqZg/7wfMA0GCSqGSIb3\nDQEBCwUAA4IBAQBZkfiVqGoJjBI37aTlLOSjLcjI75L5wBrwO39q+B4cwcmpj58P\n3sivv+jhYfAGEbQnGRzjuFoyPzWnZ1DesRExX+wrmHsLLQbF2kVjLZhEJMHF9eB7\nGZlTPdTzHErcnuXkwA/OqyXMpj9aghcQFuhCNguEfnROY9sAoK2PTfnTz9NJHL+Q\nUpDLEJEUfc0GZMVWYhahc0x38ZnSY2SKacIPECQrTI0KpqZv/P+ijCEcMD9xmYEb\njL4en+XKS1uJpw5fIU5Sj0MxhdGstH6S84iAE5J3GM3XHklGSFwwqPYvuTXvANH6\nuboynxRgSae59jIlAK6Jrr6GWMwQRbgcaAlW\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIICrjCCAjSgAwIBAgIRAOxu0I1QuMAhIeszB3fJIlkwCgYIKoZIzj0EAwMwgZYx\nCzAJBgNVBAYTAlVTMSIwIAYDVQQKDBlBbWF6b24gV2ViIFNlcnZpY2VzLCBJbmMu\nMRMwEQYDVQQLDApBbWF6b24gUkRTMQswCQYDVQQIDAJXQTEvMC0GA1UEAwwmQW1h\nem9uIFJEUyB1cy13ZXN0LTIgUm9vdCBDQSBFQ0MzODQgRzExEDAOBgNVBAcMB1Nl\nYXR0bGUwIBcNMjEwNTI0MjIwNjU5WhgPMjEyMTA1MjQyMzA2NTlaMIGWMQswCQYD\nVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjETMBEG\nA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExLzAtBgNVBAMMJkFtYXpvbiBS\nRFMgdXMtd2VzdC0yIFJvb3QgQ0EgRUNDMzg0IEcxMRAwDgYDVQQHDAdTZWF0dGxl\nMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEz4bylRcGqqDWdP7gQIIoTHdBK6FNtKH1\n4SkEIXRXkYDmRvL9Bci1MuGrwuvrka5TDj4b7e+csY0llEzHpKfq6nJPFljoYYP9\nuqHFkv77nOpJJ633KOr8IxmeHW5RXgrZo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0G\nA1UdDgQWBBQQikVz8wmjd9eDFRXzBIU8OseiGzAOBgNVHQ8BAf8EBAMCAYYwCgYI\nKoZIzj0EAwMDaAAwZQIwf06Mcrpw1O0EBLBBrp84m37NYtOkE/0Z0O+C7D41wnXi\nEQdn6PXUVgdD23Gj82SrAjEAklhKs+liO1PtN15yeZR1Io98nFve+lLptaLakZcH\n+hfFuUtCqMbaI8CdvJlKnPqT\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIIF/jCCA+agAwIBAgIQR71Z8lTO5Sj+as2jB7IWXzANBgkqhkiG9w0BAQwFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTQwOTYgRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTI0MjIwMzIwWhgPMjEyMTA1MjQyMzAzMjBaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBNDA5NiBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAM977bHIs1WJijrS\nXQMfUOhmlJjr2v0K0UjPl52sE1TJ76H8umo1yR4T7Whkd9IwBHNGKXCJtJmMr9zp\nfB38eLTu+5ydUAXdFuZpRMKBWwPVe37AdJRKqn5beS8HQjd3JXAgGKUNNuE92iqF\nqi2fIqFMpnJXWo0FIW6s2Dl2zkORd7tH0DygcRi7lgVxCsw1BJQhFJon3y+IV8/F\nbnbUXSNSDUnDW2EhvWSD8L+t4eiXYsozhDAzhBvojpxhPH9OB7vqFYw5qxFx+G0t\nlSLX5iWi1jzzc3XyGnB6WInZDVbvnvJ4BGZ+dTRpOCvsoMIn9bz4EQTvu243c7aU\nHbS/kvnCASNt+zk7C6lbmaq0AGNztwNj85Opn2enFciWZVnnJ/4OeefUWQxD0EPp\nSjEd9Cn2IHzkBZrHCg+lWZJQBKbUVS0lLIMSsLQQ6WvR38jY7D2nxM1A93xWxwpt\nZtQnYRCVXH6zt2OwDAFePInWwxUjR5t/wu3XxPgpSfrmTi3WYtr1wFypAJ811e/P\nyBtswWUQ6BNJQvy+KnOEeGfOwmtdDFYR+GOCfvCihzrKJrxOtHIieehR5Iw3cbXG\nsm4pDzfMUVvDDz6C2M6PRlJhhClbatHCjik9hxFYEsAlqtVVK9pxaz9i8hOqSFQq\nkJSQsgWw+oM/B2CyjcSqkSQEu8RLAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8w\nHQYDVR0OBBYEFPmrdxpRRgu3IcaB5BTqlprcKdTsMA4GA1UdDwEB/wQEAwIBhjAN\nBgkqhkiG9w0BAQwFAAOCAgEAVdlxWjPvVKky3kn8ZizeM4D+EsLw9dWLau2UD/ls\nzwDCFoT6euagVeCknrn+YEl7g20CRYT9iaonGoMUPuMR/cdtPL1W/Rf40PSrGf9q\nQuxavWiHLEXOQTCtCaVZMokkvjuuLNDXyZnstgECuiZECTwhexUF4oiuhyGk9o01\nQMaiz4HX4lgk0ozALUvEzaNd9gWEwD2qe+rq9cQMTVq3IArUkvTIftZUaVUMzr0O\ned1+zAsNa9nJhURJ/6anJPJjbQgb5qA1asFcp9UaMT1ku36U3gnR1T/BdgG2jX3X\nUm0UcaGNVPrH1ukInWW743pxWQb7/2sumEEMVh+jWbB18SAyLI4WIh4lkurdifzS\nIuTFp8TEx+MouISFhz/vJDWZ84tqoLVjkEcP6oDypq9lFoEzHDJv3V1CYcIgOusT\nk1jm9P7BXdTG7TYzUaTb9USb6bkqkD9EwJAOSs7DI94aE6rsSws2yAHavjAMfuMZ\nsDAZvkqS2Qg2Z2+CI6wUZn7mzkJXbZoqRjDvChDXEB1mIhzVXhiNW/CR5WKVDvlj\n9v1sdGByh2pbxcLQtVaq/5coM4ANgphoNz3pOYUPWHS+JUrIivBZ+JobjXcxr3SN\n9iDzcu5/FVVNbq7+KN/nvPMngT+gduEN5m+EBjm8GukJymFG0m6BENRA0QSDqZ7k\nzDY=\n-----END CERTIFICATE-----\n-----BEGIN CERTIFICATE-----\nMIID/jCCAuagAwIBAgIQRiwspKyrO0xoxDgSkqLZczANBgkqhkiG9w0BAQsFADCB\nlzELMAkGA1UEBhMCVVMxIjAgBgNVBAoMGUFtYXpvbiBXZWIgU2VydmljZXMsIElu\nYy4xEzARBgNVBAsMCkFtYXpvbiBSRFMxCzAJBgNVBAgMAldBMTAwLgYDVQQDDCdB\nbWF6b24gUkRTIHVzLXdlc3QtMiBSb290IENBIFJTQTIwNDggRzExEDAOBgNVBAcM\nB1NlYXR0bGUwIBcNMjEwNTI0MjE1OTAwWhgPMjA2MTA1MjQyMjU5MDBaMIGXMQsw\nCQYDVQQGEwJVUzEiMCAGA1UECgwZQW1hem9uIFdlYiBTZXJ2aWNlcywgSW5jLjET\nMBEGA1UECwwKQW1hem9uIFJEUzELMAkGA1UECAwCV0ExMDAuBgNVBAMMJ0FtYXpv\nbiBSRFMgdXMtd2VzdC0yIFJvb3QgQ0EgUlNBMjA0OCBHMTEQMA4GA1UEBwwHU2Vh\ndHRsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL53Jk3GsKiu+4bx\njDfsevWbwPCNJ3H08Zp7GWhvI3Tgi39opfHYv2ku2BKFjK8N2L6RvNPSR8yplv5j\nY0tK0U+XVNl8o0ibhqRDhbTuh6KL8CFINWYzAajuxFS+CF0U6c1Q3tXLBdALxA7l\nFlXJ71QrP06W31kRe7kvgrvO7qWU3/OzUf9qYw4LSiR1/VkvvRCTqcVNw09clw/M\nJbw6FSgweN65M9j7zPbjGAXSHkXyxH1Erin2fa+B9PE4ZDgX9cp2C1DHewYJQL/g\nSepwwcudVNRN1ibKH7kpMrgPnaNIVNx5sXVsTjk6q2ZqYw3SVHegltJpLy/cZReP\nmlivF2kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUmTcQd6o1\nCuS65MjBrMwQ9JJjmBwwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4IB\nAQAKSDSIzl956wVddPThf2VAzI8syw9ngSwsEHZvxVGHBvu5gg618rDyguVCYX9L\n4Kw/xJrk6S3qxOS2ZDyBcOpsrBskgahDFIunzoRP3a18ARQVq55LVgfwSDQiunch\nBd05cnFGLoiLkR5rrkgYaP2ftn3gRBRaf0y0S3JXZ2XB3sMZxGxavYq9mfiEcwB0\nLMTMQ1NYzahIeG6Jm3LqRqR8HkzP/Ztq4dT2AtSLvFebbNMiWqeqT7OcYp94HTYT\nzqrtaVdUg9bwyAUCDgy0GV9RHDIdNAOInU/4LEETovrtuBU7Z1q4tcHXvN6Hd1H8\ngMb0mCG5I393qW5hFsA/diFb\n-----END CERTIFICATE-----\n"}class T{static async uploadObjectArrayToTable(n,e,i,s=!1){if(r.notNullOrUndefined(n,"db"),r.notNullOrUndefined(e,"tableName"),r.notNullOrUndefined(i,"data"),t.info("Writing %d items to %s (clear: %s)",i.length,e,s),s){t.info("Clearing table %s",e);const{results:i}=await n.executeQueryWithMeta(g.Default,"DELETE FROM "+e,{});t.info("Removed %d rows",i.affectedRows)}const o=new Set(i.flatMap((n=>Object.keys(n)))),a=Array.from(o);t.info("Found columns : %j",a);const A="INSERT INTO "+e+" ("+a.join(",")+") VALUES :multiValue",{results:c}=await n.executeQueryWithMeta(g.Default,A,{multiValue:i}),l=c.affectedRows;return t.info("Wrote %d rows",l),l!==i.length&&t.warn("Should have written %d but wrote %d",i.length,l),l}}export{D as AwsRdsCert2023,B as MysqlStyleDatabaseAccess,I as NamedParameterDatabaseService,h as QueryBuilder,w as QueryBuilderResult,d as QueryUtil,u as RatchetRdbmsInfo,M as RdsMysqlStyleConnectionProvider,T as RelationalDatabaseUtils,E as SortDirection,C as SshTunnelService,g as TransactionIsolationLevel,Q as TransactionalNamedParameterDatabaseService};
2
2
  //# sourceMappingURL=index.mjs.map
package/lib/types.d.ts CHANGED
@@ -2,7 +2,7 @@ import { BuildInformation, JwtTokenBase } from '@bitblit/ratchet-common';
2
2
  import { ListenOptions, Server } from 'net';
3
3
  import { ConnectConfig, Connection } from 'ssh2';
4
4
  import * as TunnelSsh from 'tunnel-ssh';
5
- import { Connection as Connection$1, ConnectionOptions } from 'mysql2/promise';
5
+ import { ConnectionOptions, Connection as Connection$1 } from 'mysql2/promise';
6
6
 
7
7
  declare class RatchetRdbmsInfo {
8
8
  private constructor();
@@ -19,43 +19,18 @@ interface SshTunnelContainer {
19
19
  connection?: Connection;
20
20
  }
21
21
 
22
- interface SshTunnelConfig {
23
- forceLocalPort?: number;
24
- keepAlive: boolean;
25
- username: string;
26
- host: string;
27
- port: number;
28
- privateKey: string;
29
- }
30
-
31
- interface DbConfig {
32
- label: string;
33
- host: string;
34
- port: number;
35
- user: string;
36
- password: string;
37
- database: string;
38
- sshTunnelConfig?: SshTunnelConfig;
39
- }
40
-
41
- interface ConnectionAndTunnel<T> {
42
- config: DbConfig;
22
+ interface ConnectionAndTunnel<T, R> {
23
+ config: R;
43
24
  db: T;
44
25
  ssh: SshTunnelContainer;
45
26
  }
46
27
 
47
- interface ConnectionConfig {
48
- dbList: DbConfig[];
49
- }
50
-
51
28
  interface QueryResults<R> {
52
29
  results: R;
53
30
  fields?: Record<string, any>[];
54
31
  }
55
32
 
56
- interface DatabaseAccess<T, R> {
57
- getRawDatabase(): T;
58
- getRawDatabaseConfig(): R;
33
+ interface DatabaseAccess {
59
34
  close(): Promise<boolean>;
60
35
  escape(value: any): string;
61
36
  preQuery?(): Promise<void>;
@@ -73,10 +48,14 @@ interface QueryDefaults {
73
48
  timeoutMS: number;
74
49
  }
75
50
 
76
- interface DatabaseAccessProvider<T, R> {
77
- getDatabaseAccess(name?: string): Promise<DatabaseAccess<T, R> | undefined>;
51
+ interface DatabaseAccessProvider {
52
+ getDatabaseAccess(name?: string): Promise<DatabaseAccess | undefined>;
78
53
  clearDatabaseAccessCache(): Promise<boolean>;
79
- createNonPooledDatabaseAccess?(queryDefaults: QueryDefaults, additionalConfig?: R): Promise<DatabaseAccess<T, R> | undefined>;
54
+ createNonPooledDatabaseAccess?(queryDefaults: QueryDefaults, additionalConfig?: Record<string, any>): Promise<DatabaseAccess | undefined>;
55
+ }
56
+
57
+ interface DatabaseConfigList<T> {
58
+ dbList: T[];
80
59
  }
81
60
 
82
61
  interface GroupByCountResult {
@@ -130,36 +109,52 @@ interface UpdateResults {
130
109
  changedRows: number;
131
110
  }
132
111
 
112
+ interface SshTunnelConfig {
113
+ forceLocalPort?: number;
114
+ keepAlive: boolean;
115
+ username: string;
116
+ host: string;
117
+ port: number;
118
+ privateKey: string;
119
+ }
120
+
133
121
  declare class SshTunnelService {
134
122
  shutdown(ssh: SshTunnelContainer): Promise<boolean>;
135
123
  createSSHTunnel(sshOptions: SshTunnelConfig, dstHost: string, dstPort: number, localPort: number): Promise<SshTunnelContainer>;
136
124
  }
137
125
 
138
- declare class RdsMysqlStyleConnectionProvider implements DatabaseAccessProvider<Connection$1, ConnectionOptions> {
126
+ interface MysqlDbConfig {
127
+ label: string;
128
+ host: string;
129
+ port: number;
130
+ user: string;
131
+ password: string;
132
+ database: string;
133
+ sshTunnelConfig?: SshTunnelConfig;
134
+ ssl?: string | Record<string, any>;
135
+ decimalNumbers?: boolean;
136
+ }
137
+
138
+ declare class RdsMysqlStyleConnectionProvider implements DatabaseAccessProvider {
139
139
  private configPromiseProvider;
140
140
  private additionalConfig;
141
141
  private ssh?;
142
142
  static DEFAULT_CONNECTION_OPTIONS: ConnectionOptions;
143
143
  private connectionCache;
144
144
  private cacheConfigPromise;
145
- constructor(configPromiseProvider: () => Promise<ConnectionConfig>, additionalConfig?: ConnectionOptions, ssh?: SshTunnelService);
145
+ constructor(configPromiseProvider: () => Promise<DatabaseConfigList<MysqlDbConfig>>, additionalConfig?: ConnectionOptions, ssh?: SshTunnelService);
146
146
  get usingSshTunnel(): boolean;
147
147
  private addShutdownHandlerToProcess;
148
148
  clearDatabaseAccessCache(): Promise<boolean>;
149
- getConnectionAndTunnel(name: string): Promise<ConnectionAndTunnel<Connection$1>>;
150
- getDatabaseAccess(name: string): Promise<DatabaseAccess<Connection$1, ConnectionOptions> | undefined>;
151
- createNonPooledConnectionAndTunnel(queryDefaults: QueryDefaults, additionalConfig?: ConnectionOptions): Promise<ConnectionAndTunnel<Connection$1>>;
149
+ getConnectionAndTunnel(name: string): Promise<ConnectionAndTunnel<Connection$1, MysqlDbConfig>>;
150
+ getDatabaseAccess(name: string): Promise<DatabaseAccess | undefined>;
151
+ createNonPooledConnectionAndTunnel(queryDefaults: QueryDefaults, additionalConfig?: ConnectionOptions): Promise<ConnectionAndTunnel<Connection$1, MysqlDbConfig>>;
152
152
  createNonPooledDatabaseConnection(queryDefaults: QueryDefaults, additionalConfig?: ConnectionOptions): Promise<Connection$1 | undefined>;
153
153
  private getDbConfig;
154
154
  private createConnectionAndTunnel;
155
155
  private configPromise;
156
156
  private createConnectionConfig;
157
- static validDbConfig(cfg: DbConfig): string[];
158
- }
159
-
160
- interface MysqlDbConfig extends DbConfig {
161
- ssl?: string | Record<string, any>;
162
- decimalNumbers?: boolean;
157
+ static validDbConfig(cfg: MysqlDbConfig): string[];
163
158
  }
164
159
 
165
160
  interface MysqlMasterStatus {
@@ -222,7 +217,7 @@ interface MysqlSlaveStatus {
222
217
  Slave_SQL_Running_State: string;
223
218
  }
224
219
 
225
- declare class MysqlStyleDatabaseAccess implements DatabaseAccess<Connection$1, ConnectionOptions> {
220
+ declare class MysqlStyleDatabaseAccess implements DatabaseAccess {
226
221
  private _connection;
227
222
  private _connectionOptions;
228
223
  constructor(_connection: Connection$1, _connectionOptions: ConnectionOptions);
@@ -305,19 +300,19 @@ declare class QueryUtil {
305
300
  static reformatQueryForLogging(qry: string, inMaxLineLength?: number): string | null;
306
301
  }
307
302
 
308
- declare class NamedParameterDatabaseService<T, R> {
303
+ declare class NamedParameterDatabaseService {
309
304
  private queryProvider;
310
305
  private connectionProvider;
311
306
  private queryDefaults;
312
307
  private static LONG_QUERY_TIME_MS;
313
308
  private serviceName;
314
- constructor(queryProvider: QueryTextProvider, connectionProvider: DatabaseAccessProvider<T, R>, queryDefaults: QueryDefaults);
315
- nonPooledExtraConfiguration(): R;
309
+ constructor(queryProvider: QueryTextProvider, connectionProvider: DatabaseAccessProvider, queryDefaults: QueryDefaults);
310
+ nonPooledExtraConfiguration(): Record<string, any>;
316
311
  nonPooledMode(): boolean;
317
- get databaseAccessProvider(): DatabaseAccessProvider<T, R>;
312
+ get databaseAccessProvider(): DatabaseAccessProvider;
318
313
  getQueryDefaults(): QueryDefaults;
319
314
  getQueryProvider(): QueryTextProvider;
320
- createNonPooledDatabaseAccess(queryDefaults: QueryDefaults, additionalConfig?: R): Promise<DatabaseAccess<T, R>>;
315
+ createNonPooledDatabaseAccess(queryDefaults: QueryDefaults, additionalConfig?: Record<string, any>): Promise<DatabaseAccess>;
321
316
  fetchQueryRawTextByName(queryPath: string): string;
322
317
  queryBuilder(queryPath?: string): QueryBuilder;
323
318
  executeUpdateOrInsertByName(queryPath: string, params?: object, timeoutMS?: number): Promise<UpdateResults>;
@@ -336,18 +331,18 @@ declare class NamedParameterDatabaseService<T, R> {
336
331
  forceCloseConnectionForTesting(): Promise<boolean>;
337
332
  private innerExecutePreparedAsPromiseWithRetryCloseConnection;
338
333
  private innerExecutePreparedAsPromise;
339
- getDB(): Promise<DatabaseAccess<T, R>>;
334
+ getDB(): Promise<DatabaseAccess>;
340
335
  resetConnection(): Promise<boolean>;
341
336
  }
342
337
 
343
- declare class TransactionalNamedParameterDatabaseService<T, R> extends NamedParameterDatabaseService<T, R> {
338
+ declare class TransactionalNamedParameterDatabaseService extends NamedParameterDatabaseService {
344
339
  private myQueryProvider;
345
340
  private myConnectionProvider;
346
341
  private myQueryDefaults;
347
342
  private additionalConfig;
348
343
  private currentTxFlag?;
349
- constructor(myQueryProvider: QueryTextProvider, myConnectionProvider: DatabaseAccessProvider<T, R>, myQueryDefaults: QueryDefaults, additionalConfig: R);
350
- nonPooledExtraConfiguration(): R;
344
+ constructor(myQueryProvider: QueryTextProvider, myConnectionProvider: DatabaseAccessProvider, myQueryDefaults: QueryDefaults, additionalConfig: Record<string, any>);
345
+ nonPooledExtraConfiguration(): Record<string, any>;
351
346
  nonPooledMode(): boolean;
352
347
  cleanShutdown(): Promise<void>;
353
348
  startTransaction(): Promise<void>;
@@ -355,8 +350,8 @@ declare class TransactionalNamedParameterDatabaseService<T, R> extends NamedPara
355
350
  rollBackTransaction(): Promise<void>;
356
351
  buildAndExecuteUpdateOrInsertInTransaction(queryBuilder: QueryBuilder, timeoutMS?: number): Promise<UpdateResults | null>;
357
352
  buildAndExecuteInTransaction<T>(queryBuilder: QueryBuilder, timeoutMS?: number): Promise<T[] | null>;
358
- static oneStepBuildAndExecuteUpdateOrInsertInTransaction<T, R>(src: NamedParameterDatabaseService<T, R>, queryBuilder: QueryBuilder, timeoutMS?: number, additionalConfig?: R): Promise<UpdateResults | null>;
359
- static oneStepBuildAndExecuteInTransaction<S, T, R>(src: NamedParameterDatabaseService<T, R>, queryBuilder: QueryBuilder, timeoutMS?: number, additionalConfig?: R): Promise<S[] | null>;
353
+ static oneStepBuildAndExecuteUpdateOrInsertInTransaction(src: NamedParameterDatabaseService, queryBuilder: QueryBuilder, timeoutMS?: number, additionalConfig?: Record<string, any>): Promise<UpdateResults | null>;
354
+ static oneStepBuildAndExecuteInTransaction<S, T, R>(src: NamedParameterDatabaseService, queryBuilder: QueryBuilder, timeoutMS?: number, additionalConfig?: R): Promise<S[] | null>;
360
355
  }
361
356
 
362
357
  declare class AwsRdsCert2023 {
@@ -367,7 +362,7 @@ declare class AwsRdsCert2023 {
367
362
  }
368
363
 
369
364
  declare class RelationalDatabaseUtils {
370
- static uploadObjectArrayToTable<Item extends object>(db: NamedParameterDatabaseService<any, any>, tableName: string, data: Item[], clearTableFirst?: boolean): Promise<number>;
365
+ static uploadObjectArrayToTable<Item extends object>(db: NamedParameterDatabaseService, tableName: string, data: Item[], clearTableFirst?: boolean): Promise<number>;
371
366
  }
372
367
 
373
- export { AwsRdsCert2023, type ConnectionAndTunnel, type ConnectionConfig, type DatabaseAccess, type DatabaseAccessProvider, type DbConfig, type GroupByCountResult, type MysqlDbConfig, type MysqlMasterStatus, type MysqlSlaveStatus, MysqlStyleDatabaseAccess, NamedParameterDatabaseService, type PaginatedResults, type PaginationBounds, type Paginator, QueryBuilder, QueryBuilderResult, type QueryDefaults, type QueryResults, type QueryTextProvider, QueryUtil, RatchetRdbmsInfo, RdsMysqlStyleConnectionProvider, RelationalDatabaseUtils, SortDirection, type SshTunnelConfig, type SshTunnelContainer, SshTunnelService, TransactionIsolationLevel, TransactionalNamedParameterDatabaseService, type UpdateResults };
368
+ export { AwsRdsCert2023, type ConnectionAndTunnel, type DatabaseAccess, type DatabaseAccessProvider, type DatabaseConfigList, type GroupByCountResult, type MysqlDbConfig, type MysqlMasterStatus, type MysqlSlaveStatus, MysqlStyleDatabaseAccess, NamedParameterDatabaseService, type PaginatedResults, type PaginationBounds, type Paginator, QueryBuilder, QueryBuilderResult, type QueryDefaults, type QueryResults, type QueryTextProvider, QueryUtil, RatchetRdbmsInfo, RdsMysqlStyleConnectionProvider, RelationalDatabaseUtils, SortDirection, type SshTunnelConfig, type SshTunnelContainer, SshTunnelService, TransactionIsolationLevel, TransactionalNamedParameterDatabaseService, type UpdateResults };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bitblit/ratchet-rdbms",
3
- "version": "4.0.372-alpha",
3
+ "version": "4.0.374-alpha",
4
4
  "description": "Ratchet tooling for working with relational databases",
5
5
  "sideEffects": false,
6
6
  "type": "module",
@@ -48,7 +48,7 @@
48
48
  },
49
49
  "license": "Apache-2.0",
50
50
  "dependencies": {
51
- "@bitblit/ratchet-common": "4.0.372-alpha",
51
+ "@bitblit/ratchet-common": "4.0.374-alpha",
52
52
  "get-port": "7.1.0",
53
53
  "tunnel-ssh": "5.1.2"
54
54
  },
@@ -57,7 +57,7 @@
57
57
  "sqlite3": "5.1.7"
58
58
  },
59
59
  "peerDependencies": {
60
- "@bitblit/ratchet-common": "4.0.372-alpha",
60
+ "@bitblit/ratchet-common": "4.0.374-alpha",
61
61
  "get-port": "^7.1.0",
62
62
  "mysql2": "^3.10.1",
63
63
  "sqlite3": "^5.1.7",