fix: dashboard ledger fallback via health?ledger=1
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m16s
CI/CD Pipeline / Security Scanning (push) Successful in 2m27s
CI/CD Pipeline / Terraform Validation (push) Has been cancelled
CI/CD Pipeline / Kubernetes Validation (push) Has been cancelled
CI/CD Pipeline / Lint and Format (push) Has been cancelled
Validation / validate-genesis (push) Has started running
Validation / validate-terraform (push) Has been cancelled
Validation / validate-kubernetes (push) Has been cancelled
Validation / validate-smart-contracts (push) Has been cancelled
Validation / validate-security (push) Has been cancelled
Validation / validate-documentation (push) Has been cancelled

NPM proxies block dedicated money-supply paths; embed public ledger snapshot
in /health when ledger=1 and fall back from dashboard hooks.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-29 01:13:12 -07:00
parent 32f06ecc56
commit c10f6e7868
3 changed files with 57 additions and 8 deletions

View File

@@ -13,11 +13,16 @@ export type MoneySupply = {
};
async function loadMoneySupply(): Promise<MoneySupply | null> {
const publicRes = await fetch(settlementApi('/public/money-supply'));
if (publicRes.ok) return publicRes.json();
for (const path of ['/public/money-supply', '/money-supply/public']) {
const res = await fetch(settlementApi(path));
if (res.ok) return res.json();
}
const legacyRes = await fetch(settlementApi('/money-supply/public'));
if (legacyRes.ok) return legacyRes.json();
const healthRes = await fetch(`${settlementApi('/health')}?ledger=1`);
if (healthRes.ok) {
const data = (await healthRes.json()) as { moneySupply?: MoneySupply };
if (data.moneySupply) return data.moneySupply;
}
const apiKey = import.meta.env.VITE_OMNL_API_KEY;
if (!apiKey) return null;

View File

@@ -10,6 +10,19 @@ export type M2Token = DexToken & {
transferableExternal?: boolean;
};
async function loadOfficeMoneySupply(): Promise<MoneySupply | null> {
for (const path of ['/public/money-supply', '/money-supply/public']) {
const res = await fetch(settlementApi(path));
if (res.ok) return res.json();
}
const healthRes = await fetch(`${settlementApi('/health')}?ledger=1`);
if (healthRes.ok) {
const data = (await healthRes.json()) as { moneySupply?: MoneySupply };
if (data.moneySupply) return data.moneySupply;
}
return null;
}
export function useOffice24() {
const [office, setOffice] = useState<Record<string, unknown> | null>(null);
const [tokens, setTokens] = useState<M2Token[]>([]);
@@ -24,7 +37,7 @@ export function useOffice24() {
fetch(settlementApi('/office')).then((r) => r.json()),
fetch(settlementApi('/tokens/m2')).then((r) => r.json()),
fetch(exchangeApi('/health')).then((r) => r.json()),
fetch(settlementApi('/public/money-supply')).then((r) => (r.ok ? r.json() : null)),
fetch(loadOfficeMoneySupply()),
]);
setOffice(o);
setTokens(Array.isArray(t.tokens) ? t.tokens : []);

View File

@@ -57,7 +57,7 @@ export function createSettlementRouter(): Router {
const officeId = settlementOfficeId();
const profile = loadOfficeProfile();
router.get('/health', (_req, res) => {
router.get('/health', async (req, res) => {
let chainStats = { total: 0, active: 0 };
try {
const reg = loadOmnlChainRegistry();
@@ -65,7 +65,7 @@ export function createSettlementRouter(): Router {
} catch {
/* optional */
}
res.json({
const payload: Record<string, unknown> = {
service: 'omnl-settlement-middleware',
status: 'ok',
mode: process.env.SETTLEMENT_MIDDLEWARE_CONFIG?.includes('production') ? 'production' : 'standard',
@@ -77,7 +77,38 @@ export function createSettlementRouter(): Router {
name: profile.name,
},
enforceSingleOffice: loadConfig().enforceSingleOffice ?? false,
});
};
const includeLedger =
req.query.ledger === '1' ||
req.query.include === 'money-supply' ||
req.query.include === 'ledger';
if (includeLedger) {
const cfg = loadConfig();
const allow =
cfg.production.onlineBankMode || process.env.OMNL_PUBLIC_MONEY_SUPPLY === '1';
if (allow) {
try {
const [balances, fineractConnected] = await Promise.all([
fetchGlBalances(officeId),
fineractOfficeReachable(officeId),
]);
const snapshot = buildMoneySupplySnapshot(officeId, balances);
const hasActivity = Object.values(balances).some((v) => Math.abs(parseFloat(v) || 0) > 0);
payload.moneySupply = {
...snapshot,
fineractConnected,
fineractLive: fineractConnected && hasActivity,
interoffice: {
dueFromHeadOffice: balances['1410'] ?? '0',
gl1410: balances['1410'] ?? '0',
},
};
} catch (e) {
payload.moneySupplyError = e instanceof Error ? e.message : String(e);
}
}
}
res.json(payload);
});
router.get('/office', (_req, res) => {