addition of new dashboard

This commit is contained in:
2026-08-20 15:08:32 +00:00
parent 0622018d95
commit bf59249ed7
161 changed files with 13170 additions and 119 deletions

View File

@@ -0,0 +1,100 @@
import { service as defaultService } from "../modules/dashboard/service.js";
import { getConfig } from "../common/config.js";
// Same interface as the local service, so it is a drop-in for it.
//
// Tenant scoping: locally, every call carries the session's own user id.
// Remotely, the API KEY is the scope — we deliberately send NO user id, since a
// local primary key is meaningless on another operator and must never be
// trusted as a cross-operator identity.
export function makePassthrough({ service = defaultService, config = getConfig(), fetchImpl = fetch } = {}) {
const sources = () => config.dashboard || { core: {}, audit: {} };
const remote = (s) => sources()[s] && sources()[s].url;
const federated = () => Boolean(remote("core") || remote("audit"));
async function fromSource(source, endpoint, params, localCall) {
const src = sources()[source];
if (!src || !src.url) return localCall();
const res = await fetchImpl(`${src.url}/api/v1/data/dashboard/${endpoint}`, {
method: "POST",
headers: { "Content-Type": "application/json", Authorization: `Bearer ${src.key}` },
body: JSON.stringify(params),
});
if (!res.ok) throw new Error(`federation: ${source}/${endpoint} -> ${res.status}`);
return res.json();
}
const num = (v) => Number(v) || 0;
function mergeSummary(core, audit) {
const cu = core.apiUsage || {}, au = audit.apiUsage || {};
const cs = core.storage || {}, as = audit.storage || {};
const split = (c, a) => ({ core: num(c), audit: num(a), total: num(c) + num(a) });
return {
apiUsage: split(cu.core, au.audit),
apiKeys: core.apiKeys,
endpoints: core.endpoints,
storage: {
onDisk: split(cs.onDisk?.core, as.onDisk?.audit),
logical: split(cs.logical?.core, as.logical?.audit),
},
};
}
function mergeByDate(coreSeries = [], auditSeries = [], coreKey, auditKey, totalKey) {
const auditByDate = new Map(auditSeries.map((r) => [r.date, r]));
return coreSeries.map((r) => {
const a = auditByDate.get(r.date) || {};
const core = num(r[coreKey]);
const audit = num(a[auditKey]);
return { date: r.date, [coreKey]: core, [auditKey]: audit, [totalKey]: core + audit };
});
}
return {
async summary(userId, window) {
if (!federated()) return service.summary(userId, window);
const [core, audit] = await Promise.all([
fromSource("core", "summary", window, () => service.summary(userId, window)),
fromSource("audit", "summary", window, () => service.summary(userId, window)),
]);
return mergeSummary(core, audit);
},
async transactions(userId, opts) {
const source = opts.type === "audit" ? "audit" : "core";
return fromSource(source, "transactions", opts, () => service.transactions(userId, opts));
},
async series(userId, window) {
if (!federated()) return service.series(userId, window);
const [core, audit] = await Promise.all([
fromSource("core", "series", window, () => service.series(userId, window)),
fromSource("audit", "series", window, () => service.series(userId, window)),
]);
return {
usage: mergeByDate(core.usage, audit.usage, "core", "audit", "total"),
storage: mergeByDate(core.storage, audit.storage, "coreDisk", "auditDisk", "totalDisk"),
};
},
// Audit ids belong to the audit source that served the listing.
async verify(userId, targets) {
const { eventUuids = [], auditIds = [] } = targets || {};
const params = { ids: eventUuids.join(","), auditIds: auditIds.join(",") };
return fromSource("audit", "verify", params, () => service.verify(userId, targets));
},
async event(userId, eventUuid) {
return fromSource("core", "event", { eventUuid }, () => service.event(userId, eventUuid));
},
async agreement(userId, agreementUuid) {
return fromSource("core", "agreement", { agreementUuid }, () => service.agreement(userId, agreementUuid));
},
async details(userId, eventUuid) {
return fromSource("core", "details", { eventUuid }, () => service.details(userId, eventUuid))
}
};
}