react-azure-config
Version:
🚀 The Ultimate Multi-App Configuration Library! CRITICAL BUG FIXES: Prefixed environment keys no longer sent to Azure. Complete architectural redesign with bulletproof fallback system. Enterprise-grade Azure integration and monorepo support.
3 lines (2 loc) • 23.1 kB
JavaScript
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@azure/app-configuration"),require("@azure/identity"),require("@azure/keyvault-secrets")):"function"==typeof define&&define.amd?define(["exports","@azure/app-configuration","@azure/identity","@azure/keyvault-secrets"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).ReactAzureConfig={},e.AzureAppConfiguration,e.AzureIdentity,e.AzureKeyVault)}(this,function(e,t,r,i){"use strict";const o=(e,t="")=>{try{return process.env[e]||t}catch{return t}},n={isServer:"undefined"==typeof window,isClient:"undefined"!=typeof window,isBrowser:"undefined"!=typeof window&&void 0!==window.document,isDevelopment:"development"===o("NODE_ENV"),isProduction:"production"===o("NODE_ENV"),isTest:"test"===o("NODE_ENV")};const s=new class{constructor(e={}){const t=this.getDefaultLogLevel(),r=o("LOG_PREFIX","[ReactAzureConfig]");this.config={level:o("LOG_LEVEL")||t,prefix:r,enableTimestamp:n.isProduction,enableColors:!n.isProduction,...e}}getDefaultLogLevel(){return n.isProduction?"warn":n.isTest?"silent":"debug"}formatMessage(e,t){let r=`${this.config.prefix} ${t}`;if(this.config.enableTimestamp){r=`[${(new Date).toISOString()}] ${r}`}if(this.config.enableColors&&"undefined"==typeof window){r=`${{debug:"[36m",info:"[32m",warn:"[33m",error:"[31m",silent:""}[e]}${r}${"[0m"}`}return r}shouldLog(e){const t=["debug","info","warn","error","silent"],r=t.indexOf(this.config.level);return t.indexOf(e)>=r&&"silent"!==this.config.level}debug(e,...t){this.shouldLog("debug")}info(e,...t){this.shouldLog("info")}warn(e,...t){this.shouldLog("warn")}error(e,...t){this.shouldLog("error")}setLevel(e){this.config.level=e}},a=(e,t="")=>{try{return process.env[e]||t}catch{return t}},c=(e,t)=>{const r=a(e);return r?parseInt(r,10):t},l=(e,t)=>a(e,t),u={CONFIG_SERVER_PORT:c("CONFIG_SERVER_PORT",3001),APP_SERVER_PORT:c("APP_SERVER_PORT",3e3),DEFAULT_TIMEOUT:c("DEFAULT_TIMEOUT",3e4),DEFAULT_CACHE_TTL:c("CACHE_TTL",36e5),LOCAL_CONFIG_TTL:c("LOCAL_CONFIG_TTL",3e4),DEFAULT_CACHE_SIZE:c("CACHE_MAX_SIZE",1e3),MEMORY_CACHE_SIZE:c("MEMORY_CACHE_SIZE",100),MEMORY_CACHE_TTL:c("MEMORY_CACHE_TTL",3e5),CACHE_CLEANUP_INTERVAL:c("CACHE_CLEANUP_INTERVAL",6e4),MAX_RETRIES:c("MAX_RETRIES",3),RETRY_DELAY_MS:c("RETRY_DELAY_MS",1e3),DEFAULT_BASE_URL:l("DEFAULT_BASE_URL","http://localhost:3000"),CACHE_KEY_PREFIX:l("CACHE_KEY_PREFIX","react-azure-config:"),ENV_VAR_PREFIX:l("ENV_VAR_PREFIX","REACT_APP_"),DEFAULT_APPLICATION:l("DEFAULT_APPLICATION","react-app"),DEFAULT_ENVIRONMENT:l("NODE_ENV","local"),KV_SECRET_CACHE_TTL:c("AZURE_KEYVAULT_CACHE_TTL",36e5),KV_REFRESH_INTERVAL:c("AZURE_KEYVAULT_REFRESH_INTERVAL",18e5),DEFAULT_CORS_ORIGINS:((e,t)=>{const r=a(e);return r?r.split(",").map(e=>e.trim()):t})("CONFIG_SERVER_CORS_ORIGINS",["http://localhost:3000","http://localhost:3001"])},h="on-demand",d="servicePrincipal",f="managedIdentity",g="azureCli",E={AZURE:"azure",ENVIRONMENT:"environment",LOCAL:"local",DEFAULTS:"defaults"},p=(e,t,r)=>{const i=t.split(".");let o=e;for(let e=0;e<i.length-1;e++){const t=i[e];t in o||(o[t]={}),o=o[t]}o[i[i.length-1]]=r},R=e=>({api:{baseUrl:u.DEFAULT_BASE_URL,timeout:u.DEFAULT_TIMEOUT},auth:{domain:"localhost"},features:{},environment:e||u.DEFAULT_ENVIRONMENT}),C=e=>`${u.CACHE_KEY_PREFIX}${e}`,_=e=>{if("string"!=typeof e)return!1;try{const t=JSON.parse(e);return!(!t.uri||!t.uri.includes("vault.azure.net"))}catch{return!1}},y=e=>new Promise(t=>setTimeout(t,e));class m{constructor(){this.config={},this.lastLoaded=0,this.cacheTtl=u.LOCAL_CONFIG_TTL,this.loadLocalConfig()}loadLocalConfig(){const e=Date.now();e-this.lastLoaded<this.cacheTtl&&Object.keys(this.config).length>0||(this.config=this.detectAndLoadConfiguration(),this.lastLoaded=e)}detectAndLoadConfiguration(){if(this.isNodeEnvironment())try{const e=this.transformEnvToConfig(process.env);return s.debug("Loaded configuration from process.env"),e}catch(e){return s.warn("Failed to access process.env during SSR, using defaults"),R()}if(this.isBrowserEnvironment()){const e=window;if(e.ENV)return s.debug("Loaded configuration from window.ENV"),e.ENV;if(e.process?.env){const t=this.transformEnvToConfig(e.process.env);return s.debug("Loaded configuration from window.process.env"),t}return s.debug("No local configuration source found in browser"),{api:{baseUrl:"undefined"!=typeof window?window.location.origin:u.DEFAULT_BASE_URL,timeout:u.DEFAULT_TIMEOUT},environment:"browser",features:{}}}return s.debug("No local configuration source found"),R()}isNodeEnvironment(){try{return"undefined"!=typeof process&&!!process.env}catch{return!1}}isBrowserEnvironment(){return"undefined"!=typeof window}transformEnvToConfig(e){const t={};return Object.entries(e).forEach(([e,r])=>{if(e.startsWith(u.ENV_VAR_PREFIX)){const i=e.replace(u.ENV_VAR_PREFIX,"").toLowerCase().split("_").reduce((e,t,r)=>0===r?t:"url"===t||"uri"===t?e+".url":"id"===t?e+".id":e+"."+t,"");p(t,i,(e=>{if("string"!=typeof e)return e;if("true"===e.toLowerCase())return!0;if("false"===e.toLowerCase())return!1;if(/^\d+$/.test(e))return parseInt(e,10);if(/^\d*\.\d+$/.test(e))return parseFloat(e);if(e.startsWith("[")&&e.endsWith("]")||e.startsWith("{")&&e.endsWith("}"))try{return JSON.parse(e)}catch{}return e})(r))}else if(["NODE_ENV","ENVIRONMENT","ENV"].includes(e))t.environment=r;else if(e.startsWith("AZURE_")){const i=e.toLowerCase().replace("azure_","");t.azure||(t.azure={}),t.azure[i]=r}}),t.environment||(t.environment=e.NODE_ENV||"local"),t}getConfiguration(){return this.loadLocalConfig(),{...this.config}}getValue(e){this.loadLocalConfig();const t=e.split(".");let r=this.config;for(const e of t){if(!r||"object"!=typeof r||null===r||!(e in r))return;r=r[e]}return r}}class A{constructor(e={}){this.memoryCache=new Map,this.config={ttl:u.MEMORY_CACHE_TTL,maxSize:u.MEMORY_CACHE_SIZE,storage:["memory","localStorage"],...e}}get(e){const t=Date.now(),r=this.memoryCache.get(e);if(r&&r.expires>t)return r.value;if(r&&this.memoryCache.delete(e),this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable())try{const r=localStorage.getItem(C(e));if(r){const i=JSON.parse(r);if(i.expires>t)return this.memoryCache.set(e,i),i.value;localStorage.removeItem(C(e))}}catch(e){s.debug("Failed to read from localStorage:",e)}return null}set(e,t,r="unknown"){const i=Date.now(),o={value:t,timestamp:i,expires:i+this.config.ttl,source:r};if(this.memoryCache.set(e,o),this.evictOldestEntriesIfNeeded(),this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable())try{localStorage.setItem(C(e),JSON.stringify(o))}catch(e){s.debug("Failed to write to localStorage:",e),e instanceof DOMException&&"QuotaExceededError"===e.name&&this.clearLocalStorageCache()}}clear(){this.memoryCache.clear(),this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable()&&this.clearLocalStorageCache()}clearLocalStorageCache(){try{Object.keys(localStorage).forEach(e=>{e.startsWith(u.CACHE_KEY_PREFIX)&&localStorage.removeItem(e)})}catch(e){s.debug("Failed to clear localStorage cache:",e)}}cleanExpiredEntries(){const e=Date.now(),t=[];for(const[r,i]of this.memoryCache.entries())i.expires<=e&&t.push(r);t.length>0&&t.forEach(e=>{this.memoryCache.delete(e)}),this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable()&&this.cleanExpiredLocalStorageEntries(e)}cleanExpiredLocalStorageEntries(e){try{Object.keys(localStorage).forEach(t=>{if(t.startsWith(u.CACHE_KEY_PREFIX))try{const r=localStorage.getItem(t);if(r){JSON.parse(r).expires<=e&&localStorage.removeItem(t)}}catch(e){localStorage.removeItem(t)}})}catch(e){s.debug("Failed to clean localStorage expired entries:",e)}}evictOldestEntriesIfNeeded(){if(this.cleanExpiredEntries(),this.memoryCache.size>this.config.maxSize){const e=this.memoryCache.size-this.config.maxSize,t=this.memoryCache.keys();for(let r=0;r<e;r++){const e=t.next().value;e&&this.memoryCache.delete(e)}}}isLocalStorageAvailable(){try{if("undefined"==typeof window||!window.localStorage)return!1;const e="react-azure-config:test";return localStorage.setItem(e,"test"),localStorage.removeItem(e),!0}catch(e){return!1}}getStats(){const e=Date.now(),t={size:this.memoryCache.size,maxSize:this.config.maxSize,ttl:this.config.ttl,entries:Array.from(this.memoryCache.entries()).map(([t,r])=>({key:t,source:r.source,expires:r.expires,isExpired:r.expires<=e}))};let r=null;if(this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable())try{const e=Object.keys(localStorage);r={totalKeys:e.filter(e=>e.startsWith(u.CACHE_KEY_PREFIX)).length,storageUsed:JSON.stringify(localStorage).length}}catch(e){r={error:"Failed to read localStorage stats"}}return{memory:t,localStorage:r,config:this.config}}getAllKeys(){const e=Array.from(this.memoryCache.keys());if(this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable())try{const t=Object.keys(localStorage).filter(e=>e.startsWith(u.CACHE_KEY_PREFIX)).map(e=>e.replace(u.CACHE_KEY_PREFIX,""));return Array.from(new Set([...e,...t]))}catch(t){return e}return e}delete(e){const t=this.memoryCache.delete(e);if(this.config.storage.includes("localStorage")&&this.isLocalStorageAvailable())try{return localStorage.removeItem(C(e)),!0}catch(e){return t}return t}getConfig(){return{...this.config}}}var S;!function(e){e.CONFIGURATION_ERROR="CONFIGURATION_ERROR",e.AZURE_CLIENT_ERROR="AZURE_CLIENT_ERROR",e.NETWORK_ERROR="NETWORK_ERROR",e.CACHE_ERROR="CACHE_ERROR",e.KEYVAULT_ERROR="KEYVAULT_ERROR",e.VALIDATION_ERROR="VALIDATION_ERROR",e.SERVER_ERROR="SERVER_ERROR"}(S||(S={}));class v extends Error{constructor(e,t,r,i){super(t),this.name="ConfigurationError",this.type=e,this.context=r,this.originalError=i,Error.captureStackTrace&&Error.captureStackTrace(this,v)}toJSON(){return{name:this.name,type:this.type,message:this.message,context:this.context,stack:this.stack,originalError:this.originalError?.message}}}const T=(e,t,r,i="error")=>{const o=e instanceof Error?e:void 0,n=e instanceof Error?e.message:String(e),a=new v(t,n,r,o);return s[i](`${t}: ${n}`,{context:r,originalError:o?.stack}),a};class I{constructor(e){this.client=null,this.localProvider=null,this.retryCount=0,this.maxRetries=u.MAX_RETRIES,this.keyVaultClients=new Map,this.credential=null,this.configurationLoaded=!1,this.options={application:u.DEFAULT_APPLICATION,enableLocalFallback:!0,sources:[E.AZURE,E.ENVIRONMENT,E.LOCAL,E.DEFAULTS],precedence:"first-wins",logLevel:"warn",...e},e.logLevel&&s.setLevel(e.logLevel),this.cache=new A({ttl:u.DEFAULT_CACHE_TTL,maxSize:u.DEFAULT_CACHE_SIZE,storage:["memory","localStorage"],refreshStrategy:h,...e.cache}),this.keyVaultConfig={enableKeyVaultReferences:!0,secretCacheTtl:u.KV_SECRET_CACHE_TTL,maxRetries:u.MAX_RETRIES,retryDelayMs:u.RETRY_DELAY_MS,refreshStrategy:h,...e.keyVault},"local"===this.options.environment?this.localProvider=new m:this.options.endpoint&&this.initializeAzureClient(),this.setupPeriodicRefresh()}initializeAzureClient(){try{this.credential=this.createCredential(),this.client=new t.AppConfigurationClient(this.options.endpoint,this.credential),s.debug("Azure App Configuration client initialized")}catch(e){const t=T(e,S.AZURE_CLIENT_ERROR,{endpoint:this.options.endpoint,environment:this.options.environment});if(!this.options.enableLocalFallback)throw t;s.info("Falling back to local configuration"),this.localProvider=new m}}createCredential(){const e=this.options.authentication;if(e?.type===d){if(!e.tenantId||!e.clientId||!e.clientSecret)throw T("Service Principal authentication requires tenantId, clientId, and clientSecret",S.VALIDATION_ERROR,{authType:e.type});return s.debug(`Using Service Principal authentication for tenant: ${e.tenantId}`),new r.ClientSecretCredential(e.tenantId,e.clientId,e.clientSecret)}if(e?.type===f){s.debug("Using Managed Identity authentication");const t=e.clientId?{managedIdentityClientId:e.clientId}:void 0;return new r.DefaultAzureCredential(t)}return e?.type===g?(s.debug("Using Azure CLI authentication"),new r.DefaultAzureCredential):(s.debug("Using DefaultAzureCredential"),new r.DefaultAzureCredential)}async getConfiguration(){const e=`config:${this.options.environment}:${this.options.application}`,t=this.cache.getConfig().refreshStrategy||"on-demand";if("load-once"===t&&this.configurationLoaded){const t=this.cache.get(e);if(t)return s.debug("Using cached configuration (load-once strategy)"),t}const r=this.cache.get(e);if(r&&"load-once"!==t)return r;const i=this.options.sources||["azure","environment","local","defaults"];for(const t of i)try{const r=await this.loadFromSource(t);if(r&&Object.keys(r).length>0)return this.cache.set(e,r,t),this.configurationLoaded=!0,s.debug(`Configuration loaded from ${t}`),r}catch(r){if(s.warn(`Failed to load from ${t}:`,r),"azure"===t&&this.retryCount<this.maxRetries){this.retryCount++,s.debug(`Retrying Azure load (${this.retryCount}/${this.maxRetries})`),await y(Math.pow(2,this.retryCount)*u.RETRY_DELAY_MS);try{const r=await this.loadFromSource(t);if(r&&Object.keys(r).length>0)return this.cache.set(e,r,t),this.configurationLoaded=!0,this.retryCount=0,r}catch(e){T(e,S.CONFIGURATION_ERROR,{source:t,retryAttempt:this.retryCount,maxRetries:this.maxRetries},"warn")}}continue}throw T(`Failed to load configuration from all sources: ${i.join(", ")}`,S.CONFIGURATION_ERROR,{sources:i,environment:this.options.environment})}async loadFromSource(e){switch(e){case"azure":return await this.loadFromAzure();case"environment":case"local":return this.localProvider||(this.localProvider=new m),this.localProvider.getConfiguration();case E.DEFAULTS:return R(this.options.environment);default:throw T(`Unknown configuration source: ${e}`,S.VALIDATION_ERROR,{source:e,availableSources:Object.values(E)})}}async loadFromAzure(){if(!this.client)throw T("Azure client not initialized",S.AZURE_CLIENT_ERROR,{endpoint:this.options.endpoint});const e={},t=this.options.application?`${this.options.application}:*`:void 0,r=this.options.label||("local"===this.options.environment?"\0":this.options.environment);try{s.debug(`Loading from Azure - App: ${t}, Label: ${r}`);const i={labelFilter:r};t&&(i.keyFilter=t);const o=this.client.listConfigurationSettings(i);let n=0;for await(const t of o)if(t.key&&void 0!==t.value){const r=this.options.application?t.key.replace(`${this.options.application}:`,""):t.key;let i=t.value;if(this.keyVaultConfig.enableKeyVaultReferences&&_(t.value))try{i=await this.resolveKeyVaultReference(t.value)||t.value}catch(e){s.warn(`Failed to resolve Key Vault reference for "${r}":`,e),i=t.value}p(e,r,i),n++}return s.debug(`Loaded ${n} settings from Azure`),e}catch(e){throw s.error("Error loading from Azure:",e),e}}async getValue(e){const t=await this.getConfiguration(),r=e.split(".");let i=t;for(const e of r){if(!i||"object"!=typeof i||null===i||!(e in i))return;i=i[e]}return i}async refreshConfiguration(e=!1){const t=this.cache.getConfig().refreshStrategy||"on-demand";e||"load-once"!==t?(this.cache.clear(),this.retryCount=0,this.configurationLoaded=!1,await this.getConfiguration()):s.debug("Refresh ignored - using load-once strategy")}getEnvironment(){return this.options.environment}getCacheStats(){return this.cache.getStats()}parseKeyVaultReference(e){try{const t=new URL(e),r=t.pathname.split("/");return r.length<3||"secrets"!==r[1]?{}:{vaultUrl:`${t.protocol}//${t.hostname}`,secretName:r[2],secretVersion:r[3]}}catch{return{}}}async resolveKeyVaultReference(e){try{const t=JSON.parse(e);if(!t.uri)return null;const{vaultUrl:r,secretName:i,secretVersion:o}=this.parseKeyVaultReference(t.uri);if(!r||!i)return s.warn("Invalid Key Vault reference format:",e),null;const n=this.getKeyVaultClient(r);if(!n)return null;const a=`keyvault:${r}:${i}:${o||"latest"}`,c=this.keyVaultConfig.refreshStrategy||"on-demand",l=this.cache.get(a);if(l)return"load-once"===c?(s.debug(`Using cached Key Vault secret: ${i}`),l):l;const u=await this.fetchSecretWithRetry(n,i,o);return u&&(this.cache.set(a,u,"keyvault"),s.debug(`Resolved Key Vault secret: ${i}`)),u}catch(e){return s.error("Error resolving Key Vault reference:",e),null}}getKeyVaultClient(e){if(!this.credential)return s.error("No credential available for Key Vault access"),null;if(this.keyVaultClients.has(e))return this.keyVaultClients.get(e);try{const t=new i.SecretClient(e,this.credential);return this.keyVaultClients.set(e,t),s.debug(`Created Key Vault client for: ${e}`),t}catch(t){return s.error(`Failed to create Key Vault client for ${e}:`,t),null}}async fetchSecretWithRetry(e,t,r){const i=this.keyVaultConfig.maxRetries||u.MAX_RETRIES,o=this.keyVaultConfig.retryDelayMs||u.RETRY_DELAY_MS;for(let n=0;n<=i;n++)try{return(r?await e.getSecret(t,{version:r}):await e.getSecret(t)).value||null}catch(e){if(n===i)throw"Forbidden"===e.code||403===e.statusCode?s.error(`Access denied to Key Vault secret "${t}"`):"SecretNotFound"===e.code||404===e.statusCode?s.error(`Key Vault secret "${t}" not found`):s.error(`Error fetching Key Vault secret "${t}":`,e),e;s.debug(`Key Vault access attempt ${n+1} failed, retrying...`),await y(o*Math.pow(2,n))}return null}setupPeriodicRefresh(){const e=this.cache.getConfig(),t=e.refreshStrategy||"on-demand";if("periodic"===t){const t=e.refreshInterval||36e5;s.debug(`Setting up periodic refresh every ${t}ms`),setInterval(async()=>{try{s.debug("Performing periodic configuration refresh"),await this.refreshConfiguration()}catch(e){s.error("Periodic refresh failed:",e)}},t)}const r=this.keyVaultConfig.refreshStrategy||"on-demand";if("periodic"===r&&r!==t){const e=this.keyVaultConfig.refreshInterval||18e5;s.debug(`Setting up periodic Key Vault refresh every ${e}ms`),setInterval(async()=>{try{s.debug("Performing periodic Key Vault cache refresh"),this.clearKeyVaultCache()}catch(e){s.error("Periodic Key Vault refresh failed:",e)}},e)}}clearKeyVaultCache(){const e=this.cache.getAllKeys().filter(e=>e.startsWith("keyvault:"));e.forEach(e=>this.cache.delete(e)),s.debug(`Cleared ${e.length} Key Vault cache entries`)}}e.ConfigurationCache=A,e.LocalConfigurationProvider=m,e.default=class{constructor(e){this.azureClient=null,this.options={sources:[E.AZURE,E.ENVIRONMENT,E.LOCAL,E.DEFAULTS],precedence:"first-wins",useEmbeddedService:!0,configServiceUrl:`http://localhost:${u.CONFIG_SERVER_PORT}`,port:u.CONFIG_SERVER_PORT,...e},this.appId=this.options.appId,this.cache=new A(e.cache),this.serviceUrl=this.options.configServiceUrl||`http://localhost:${this.options.port||u.CONFIG_SERVER_PORT}`,!this.options.useEmbeddedService&&this.options.endpoint&&(this.azureClient=new I(e))}buildConfigEndpoint(){return""}buildConfigValueEndpoint(e){return""}buildRefreshEndpoint(){return"/refresh"}buildCacheKey(e=""){const t=this.appId?`${this.appId}:${this.options.environment}`:this.options.environment;return e?`${e}:${t}`:`config:${t}`}async getConfiguration(){const e=this.buildCacheKey(),t=this.cache.get(e);if(t)return t;let r,i;try{if(this.options.useEmbeddedService){const e=await this.fetchFromService(this.buildConfigEndpoint());r=e.config?e.config:e.data?e.data:{},i=e.source||"api",0===Object.keys(r).length&&(r=this.getEnvironmentFallback(),i="environment-fallback",Object.keys(r).length)}else{if(!this.azureClient)throw T("Azure client not initialized",S.AZURE_CLIENT_ERROR,{useEmbeddedService:!1});r=await this.azureClient.getConfiguration(),i="azure"}return this.cache.set(e,r,i),r}catch(t){t instanceof Error?t.message:String(t);try{if(r=this.getEnvironmentFallback(),i="environment-fallback",Object.keys(r).length>0)return this.cache.set(e,r,i),r}catch(e){e instanceof Error?e.message:String(e)}T(t,S.CONFIGURATION_ERROR,{useEmbeddedService:this.options.useEmbeddedService,serviceUrl:this.serviceUrl,appId:this.appId});const o=this.cache.get(e);if(o)return s.warn("Returning stale cached configuration due to error",{appId:this.appId}),o;const n=R(this.options.environment);return this.cache.set(e,n,"defaults"),n}}async getValue(e){try{const t=((e,t)=>{const r=t.split(".");let i=e;for(const e of r){if(!i||"object"!=typeof i||null===i||!(e in i))return;i=i[e]}return i})(await this.getConfiguration(),e);if(void 0===t){const t=this.getEnvironmentValue(e);if(void 0!==t)return t}return t}catch(t){try{const t=this.getEnvironmentValue(e);if(void 0!==t)return t}catch(e){}return void s.error(`Failed to get config value for key "${e}":`,t,{appId:this.appId})}}async refreshConfiguration(){try{this.options.useEmbeddedService?await this.fetchFromService(this.buildRefreshEndpoint(),{method:"POST"}):this.azureClient&&await this.azureClient.refreshConfiguration(),this.cache.clear()}catch(e){throw s.error("Failed to refresh configuration:",e,{appId:this.appId}),e}}async fetchFromService(e,t={}){const r=e?`${this.serviceUrl}${e}`:this.serviceUrl,i=await fetch(r,{headers:{"Content-Type":"application/json",...t.headers},...t});if(!i.ok)throw T(`Config service error: ${i.status} ${i.statusText}`,S.SERVER_ERROR,{url:r,status:i.status,statusText:i.statusText});const o=await i.json();if(!o.success&&o.error)throw T(`Config service error: ${o.error}`,S.SERVER_ERROR,{endpoint:e,apiError:o.error});return o}getEnvironmentFallback(){const e={},t=[this.appId?`REACT_APP_${this.appId.toUpperCase().replace(/-/g,"_")}_`:null,this.appId?`${this.appId.toUpperCase().replace(/-/g,"_")}_`:null,"REACT_APP_","NEXTAUTH_","OKTA_","AZURE_","AUTH_","API_","DATABASE_","SGJ_"].filter(Boolean);Object.keys(process.env).forEach(r=>{const i=process.env[r];if(void 0!==i){if(t.some(e=>r.startsWith(e))){const t=this.transformEnvironmentKey(r);e[t]=i,e[r]=i,r.includes("NEXTAUTH_SECRET")&&(e["nextauth.secret"]=i,e.nextauthsecret=i),r.includes("OKTA_CLIENT_ID")&&(e["okta.client.id"]=i,e.oktaclientid=i)}}});return["NEXTAUTH_SECRET","OKTA_CLIENT_ID","OKTA_CLIENT_SECRET","OKTA_ISSUER","SGJ_INVESTMENT_BASE_URL","API_URL","DATABASE_URL"].forEach(t=>{if(!e[t]){const r=this.getEnvironmentValue(t);if(void 0!==r){const i=t.toLowerCase().replace(/_/g,".");e[i]=r,e[t]=r}}}),e}transformEnvironmentKey(e){let t=e;if(this.appId){const e=this.appId.toUpperCase().replace(/-/g,"_"),r=[`REACT_APP_${e}_`,`${e}_`];for(const e of r)if(t.startsWith(e)){t=t.substring(e.length);break}}const r=["REACT_APP_"];for(const e of r)if(t.startsWith(e)){t=t.substring(e.length);break}return t.toLowerCase().replace(/_/g,".")}getEnvironmentValue(e){if("undefined"==typeof process)return;const t=[e,`REACT_APP_${e}`,this.appId?`REACT_APP_${this.appId.toUpperCase()}_${e}`:null,this.appId?`${this.appId.toUpperCase()}_${e}`:null].filter(Boolean);for(const e of t){const t=process.env[e];if(void 0!==t)return t}}getEnvironment(){return this.options.environment}getAppId(){return this.appId}getCacheStats(){return this.cache.getStats()}isUsingEmbeddedService(){return this.options.useEmbeddedService||!1}async checkServiceHealth(){if(!this.options.useEmbeddedService)return{status:"not-applicable",reason:"Direct mode"};try{return(await this.fetchFromService("/health")).data}catch(e){return{status:"unhealthy",error:e.message}}}getServiceUrl(){return this.serviceUrl}},Object.defineProperty(e,"__esModule",{value:!0})});
//# sourceMappingURL=index.umd.min.js.map