@creditkarma/dynamic-config
Version:
Dynamic Config for Node.js backed by Consul and Vault
111 lines • 3.71 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.resolveConfigPromises = exports.valuesForPromises = void 0;
const ConfigUtils = require("./config");
const ConfigBuilder = require("./config-builder");
/**
* Recursively traverses an object, looking for keys with Promised values and returns a Promise of
* the object with all nested Promises resolved.
*/
async function valuesForPromises(promises) {
return Promise.all(promises.map((next, index) => {
return resolveAtIndex(next, index);
})).then((values) => {
return processValues(values);
});
}
exports.valuesForPromises = valuesForPromises;
function processValues(values) {
return values
.sort((a, b) => {
if (a[1] < b[1]) {
return -1;
}
else {
return 1;
}
})
.map((next) => {
return next[0];
});
}
function resolveAtIndex(promise, index) {
return new Promise((resolve, reject) => {
promise.then((val) => {
return resolve([val, index]);
});
});
}
function appendUpdatesForObject(value, path, updates) {
if (value instanceof Promise) {
updates.push([path, value]);
}
else if (typeof value === 'object') {
collectUnresolvedPromises(value, path, updates);
}
}
async function handleUnresolved(unresolved, base) {
const paths = unresolved.map((next) => next[0].join('.'));
const promises = unresolved.map((next) => next[1]);
const resolvedPromises = await Promise.all(promises.map((next) => {
return next.then((val) => {
const nested = collectUnresolvedPromises(val);
if (nested.length > 0) {
return handleUnresolved(nested, val);
}
else {
return Promise.resolve(val);
}
});
}));
const newObj = resolvedPromises.reduce((acc, next, currentIndex) => {
return ConfigUtils.setValueForKey(paths[currentIndex], next, acc);
}, base);
return newObj;
}
function collectUnresolvedPromises(configValue, path = [], updates = []) {
if (configValue.type === 'array') {
for (let i = 0; i < configValue.items.length; i++) {
const value = configValue.items[i];
const newPath = [...path, `${i}`];
appendUpdatesForObject(value, newPath, updates);
}
return updates;
}
else if (configValue.type === 'promise') {
updates.push([
path,
configValue.value.then((value) => {
return ConfigBuilder.buildBaseConfigValue(configValue.source, value);
}),
]);
return updates;
}
else if (configValue.type === 'object' || configValue.type === 'root') {
for (const key of Object.keys(configValue.properties)) {
const value = configValue.properties[key];
const newPath = [...path, key];
appendUpdatesForObject(value, newPath, updates);
}
return updates;
}
else {
return [];
}
}
async function resolveConfigPromises(configValue) {
if (configValue.type === 'promise') {
return configValue.value.then((val) => {
return resolveConfigPromises(ConfigBuilder.buildBaseConfigValue(configValue.source, val));
});
}
else if (configValue.type === 'object' || configValue.type === 'root') {
const unresolved = collectUnresolvedPromises(configValue);
return handleUnresolved(unresolved, configValue);
}
else {
return configValue;
}
}
exports.resolveConfigPromises = resolveConfigPromises;
//# sourceMappingURL=config-promises.js.map