zephyr-agent
Version:
Zephyr plugin agent
100 lines (99 loc) • 4.56 kB
JavaScript
import "node:module";
import { ze_api_gateway } from "zephyr-edge-contract";
import { isTokenStillValid } from "../auth/login.mjs";
import { ZeErrors, ZephyrError } from "../errors/index.mjs";
import { makeRequest } from "../http/http-request.mjs";
import { ze_log } from "../logging/index.mjs";
import { getAppConfig, getApplicationConfigStorageScope, saveAppConfig } from "../node-persist/application-configuration.mjs";
import { getToken } from "../node-persist/token.mjs";
const APPLICATION_CONFIG_TTL_MS = 60000;
const inFlightByIdentity = new Map();
const cachedConfigByIdentity = new Map();
function getApplicationIdentity(scope, application_uid) {
return JSON.stringify([
scope.apiEndpoint,
scope.apiGatewayEndpoint,
scope.environment,
scope.preview,
scope.principalFingerprint,
application_uid
]);
}
function isIdentityForApplication(identity, application_uid) {
try {
const parsed = JSON.parse(identity);
return Array.isArray(parsed) && parsed[parsed.length - 1] === application_uid;
} catch {
return false;
}
}
function isValidConfig(config, application_uid) {
return Boolean(config && config.application_uid === application_uid && isTokenStillValid(config.jwt) && config.fetched_at && Date.now() - config.fetched_at <= APPLICATION_CONFIG_TTL_MS);
}
async function loadApplicationConfiguration({ application_uid }, scope, token) {
if (!application_uid) throw new ZephyrError(ZeErrors.ERR_MISSING_APPLICATION_UID);
const application_config_url = new URL(`${ze_api_gateway.application_config}/${application_uid}`, scope.apiGatewayEndpoint);
const [ok, cause, data] = await makeRequest(application_config_url, {
headers: {
Authorization: `Bearer ${token}`
},
credentialToken: token
});
if (!ok || !data?.value || data.value.application_uid !== application_uid) throw new ZephyrError(ZeErrors.ERR_LOAD_APP_CONFIG, {
application_uid,
operation: 'get-application-config',
cause,
data: {
url: application_config_url.toString()
}
});
return {
...data.value,
fetched_at: Date.now()
};
}
async function getApplicationConfiguration({ application_uid }) {
try {
if (!application_uid) throw new ZephyrError(ZeErrors.ERR_MISSING_APPLICATION_UID);
const token = await getToken();
const scope = getApplicationConfigStorageScope(token);
const identity = getApplicationIdentity(scope, application_uid);
const cachedConfig = cachedConfigByIdentity.get(identity);
if (isValidConfig(cachedConfig, application_uid)) {
ze_log.app('Using cached application configuration');
return cachedConfig;
}
cachedConfigByIdentity.delete(identity);
const existingRequest = inFlightByIdentity.get(identity);
if (existingRequest) return existingRequest;
ze_log.app('Getting application configuration from node-persist');
const request = (async ()=>{
const storedAppConfig = await getAppConfig(application_uid, scope);
if (isValidConfig(storedAppConfig, application_uid)) return storedAppConfig;
{
ze_log.app('Loading Application Configuration from API...');
const loadedAppConfig = await loadApplicationConfiguration({
application_uid
}, scope, token);
ze_log.app('Saving Application Configuration to node-persist...');
await saveAppConfig(application_uid, loadedAppConfig, scope);
return loadedAppConfig;
}
})().then((config)=>{
cachedConfigByIdentity.set(identity, config);
return config;
}).finally(()=>{
if (inFlightByIdentity.get(identity) === request) inFlightByIdentity.delete(identity);
});
inFlightByIdentity.set(identity, request);
return await request;
} catch (error) {
throw ZephyrError.withContext(error, 'get-application-config');
}
}
function invalidateApplicationConfigCache(application_uid) {
if (!application_uid) return void cachedConfigByIdentity.clear();
for (const identity of cachedConfigByIdentity.keys())if (isIdentityForApplication(identity, application_uid)) cachedConfigByIdentity.delete(identity);
}
export { getApplicationConfiguration, invalidateApplicationConfigCache };
//# sourceMappingURL=get-application-configuration.mjs.map