48 lines
2.3 KiB
JavaScript
48 lines
2.3 KiB
JavaScript
// Generated, do not edit. sha256:e34176fb1b8095153c2f85bcad4807088cce9195b029b64bb8721d0f3610d90d
|
|
export const HISTORY_CAPABILITIES = Object.freeze(['daily_history', 'history_point']);
|
|
|
|
const has = (p, cap) => Array.isArray(p.endpoints) && p.endpoints.some(e => e.capability === cap);
|
|
const covers = (p, symbol) => Array.isArray(p.coverage) && p.coverage.includes(symbol);
|
|
const deliversHistory = p => HISTORY_CAPABILITIES.some(cap => has(p, cap));
|
|
|
|
export function diagnoseSources(asset, { providers = [], historyChain = [], usage = {}, serviceCovers = false } = {}) {
|
|
if (!asset) return [];
|
|
const byKey = new Map(providers.map(p => [p.key, p]));
|
|
const candidates = providers.filter(p => !p.isSystem && !p.fixedRate && covers(p, asset.symbol) && deliversHistory(p));
|
|
if (!candidates.length) return serviceCovers ? [] : [{ severity: 'problem', code: 'noCoverage' }];
|
|
const active = candidates.filter(p => p.isActive);
|
|
if (!active.length) return serviceCovers ? [] : [{ severity: 'problem', code: 'allInactive', names: candidates.map(p => p.name) }];
|
|
|
|
const chosen = [], unusable = [];
|
|
for (const key of historyChain) {
|
|
const p = byKey.get(key);
|
|
if (!p) continue;
|
|
const usable = p.isActive && deliversHistory(p) && covers(p, asset.symbol);
|
|
(usable ? chosen : unusable).push(p);
|
|
}
|
|
const unique = list => [...new Map(list.map(p => [p.id, p])).values()];
|
|
if (!chosen.length) {
|
|
if (serviceCovers) return [];
|
|
const proposal = proposalFrom(active);
|
|
return [{ severity: 'problem', code: unusable.length ? 'choiceUnusable' : 'noChoice',
|
|
names: unique(unusable).map(p => p.name), proposal }];
|
|
}
|
|
const out = [];
|
|
const atLimit = unique(chosen).filter(p => p.callsPerMonth && (usage[p.id] ?? 0) >= p.callsPerMonth);
|
|
if (atLimit.length) {
|
|
out.push({ severity: atLimit.length === unique(chosen).length && !serviceCovers ? 'problem' : 'attention',
|
|
code: 'limitReached', names: atLimit.map(p => p.name) });
|
|
}
|
|
const off = unique(unusable).filter(p => !p.isActive);
|
|
if (off.length) out.push({ severity: 'attention', code: 'choiceInactive', names: off.map(p => p.name) });
|
|
return out;
|
|
}
|
|
|
|
function proposalFrom(active) {
|
|
for (const cap of HISTORY_CAPABILITIES) {
|
|
const p = active.find(x => has(x, cap));
|
|
if (p) return { providerKey: p.key, providerId: p.id, providerName: p.name, capability: 'history' };
|
|
}
|
|
return null;
|
|
}
|