fix: dashboard API paths for nginx/NPM proxy routing
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m18s
CI/CD Pipeline / Security Scanning (push) Successful in 2m45s
CI/CD Pipeline / Lint and Format (push) Failing after 47s
CI/CD Pipeline / Terraform Validation (push) Failing after 28s
CI/CD Pipeline / Kubernetes Validation (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
Some checks failed
CI/CD Pipeline / Solidity Contracts (push) Failing after 1m18s
CI/CD Pipeline / Security Scanning (push) Successful in 2m45s
CI/CD Pipeline / Lint and Format (push) Failing after 47s
CI/CD Pipeline / Terraform Validation (push) Failing after 28s
CI/CD Pipeline / Kubernetes Validation (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
Use short /settlement and /exchange paths in production so nginx maps them to backend /api/v1/* without double-prefix 404s. Align all nginx configs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -11,7 +11,7 @@ location /api/v1/ {
|
||||
}
|
||||
|
||||
location /settlement/ {
|
||||
proxy_pass http://omnl_settlement/;
|
||||
proxy_pass http://omnl_settlement/api/v1/settlement/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
@@ -22,7 +22,7 @@ location /settlement/ {
|
||||
}
|
||||
|
||||
location /exchange/ {
|
||||
proxy_pass http://omnl_exchange/;
|
||||
proxy_pass http://omnl_exchange/api/v1/exchange/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
|
||||
@@ -40,14 +40,14 @@ http {
|
||||
}
|
||||
|
||||
location /settlement/ {
|
||||
proxy_pass http://omnl_lxc_settlement/;
|
||||
proxy_pass http://omnl_lxc_settlement/api/v1/settlement/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 120s;
|
||||
}
|
||||
|
||||
location /exchange/ {
|
||||
proxy_pass http://omnl_lxc_exchange/;
|
||||
proxy_pass http://omnl_lxc_exchange/api/v1/exchange/;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 120s;
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>OMNL Mission Control — Chain 138</title>
|
||||
<title>OMNL Mission Control - Chain 138</title>
|
||||
<style>
|
||||
html, body { margin: 0; min-height: 100%; background: #0f2847; color: #e8f4ff; }
|
||||
#root { min-height: 100vh; }
|
||||
@@ -33,7 +33,7 @@
|
||||
<div id="root">
|
||||
<div class="omnl-boot" role="status" aria-live="polite">
|
||||
<div class="omnl-boot__title">OMNL Mission Control</div>
|
||||
<div class="omnl-boot__hint">Loading dashboard…</div>
|
||||
<div class="omnl-boot__hint">Loading dashboard...</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
|
||||
@@ -22,6 +22,24 @@ export const SETTLEMENT_MIDDLEWARE_URL = prodOrLocal(
|
||||
'/settlement',
|
||||
'http://localhost:3011',
|
||||
);
|
||||
|
||||
/** Production nginx maps /settlement/* → settlement-middleware /api/v1/settlement/* */
|
||||
function proxiedServiceUrl(base: string, servicePrefix: string, path: string): string {
|
||||
const root = base.replace(/\/$/, '');
|
||||
const suffix = path.startsWith('/') ? path : `/${path}`;
|
||||
if (root.startsWith('/')) {
|
||||
return `${root}${suffix}`;
|
||||
}
|
||||
return `${root}${servicePrefix}${suffix}`;
|
||||
}
|
||||
|
||||
export function settlementApi(path: string): string {
|
||||
return proxiedServiceUrl(SETTLEMENT_MIDDLEWARE_URL, '/api/v1/settlement', path);
|
||||
}
|
||||
|
||||
export function exchangeApi(path: string): string {
|
||||
return proxiedServiceUrl(DBIS_EXCHANGE_URL, '/api/v1/exchange', path);
|
||||
}
|
||||
export const ENHANCED_SWAP_ROUTER_V2 =
|
||||
import.meta.env.VITE_ENHANCED_SWAP_ROUTER_V2 ||
|
||||
'0xa421706768aeb7fafa2d912c5e10824ef3437ad4';
|
||||
@@ -66,7 +84,7 @@ export function formatAmountFromWei(wei: string, decimals: number): string {
|
||||
}
|
||||
export async function fetchExchangeTokens(): Promise<DexToken[]> {
|
||||
try {
|
||||
const res = await fetch(`${DBIS_EXCHANGE_URL.replace(/\/$/, '')}/api/v1/exchange/tokens`);
|
||||
const res = await fetch(exchangeApi('/tokens'));
|
||||
if (!res.ok) return DEFAULT_TOKENS;
|
||||
const data = await res.json();
|
||||
return Array.isArray(data.tokens) && data.tokens.length > 0 ? data.tokens : DEFAULT_TOKENS;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { SETTLEMENT_MIDDLEWARE_URL } from './dex';
|
||||
import { settlementApi } from './dex';
|
||||
|
||||
export type OmnlChainSummary = {
|
||||
chainId: number;
|
||||
@@ -21,8 +21,7 @@ export type ChainRegistryResponse = {
|
||||
|
||||
export async function fetchOmnlChainRegistry(): Promise<ChainRegistryResponse | null> {
|
||||
try {
|
||||
const base = SETTLEMENT_MIDDLEWARE_URL.replace(/\/$/, '');
|
||||
const res = await fetch(`${base}/api/v1/settlement/chains`);
|
||||
const res = await fetch(settlementApi('/chains'));
|
||||
if (!res.ok) return null;
|
||||
return res.json();
|
||||
} catch {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { DBIS_EXCHANGE_URL, SETTLEMENT_MIDDLEWARE_URL } from '../../config/dex';
|
||||
import { exchangeApi, settlementApi } from '../../config/dex';
|
||||
|
||||
export type MoneySupply = {
|
||||
asOf?: string;
|
||||
@@ -12,14 +12,14 @@ export type MoneySupply = {
|
||||
M2?: { broadMoney?: string; gl2200?: string; metaFiatPending?: string };
|
||||
};
|
||||
|
||||
async function loadMoneySupply(settlement: string): Promise<MoneySupply | null> {
|
||||
const publicRes = await fetch(`${settlement}/api/v1/settlement/money-supply/public`);
|
||||
async function loadMoneySupply(): Promise<MoneySupply | null> {
|
||||
const publicRes = await fetch(settlementApi('/money-supply/public'));
|
||||
if (publicRes.ok) return publicRes.json();
|
||||
|
||||
const apiKey = import.meta.env.VITE_OMNL_API_KEY;
|
||||
if (!apiKey) return null;
|
||||
|
||||
const authRes = await fetch(`${settlement}/api/v1/settlement/money-supply`, {
|
||||
const authRes = await fetch(settlementApi('/money-supply'), {
|
||||
headers: { Authorization: `Bearer ${apiKey}` },
|
||||
});
|
||||
return authRes.ok ? authRes.json() : null;
|
||||
@@ -34,19 +34,16 @@ export function useCentralBank() {
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const settlement = SETTLEMENT_MIDDLEWARE_URL.replace(/\/$/, '');
|
||||
const exchange = DBIS_EXCHANGE_URL.replace(/\/$/, '');
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const [h, o, m2, mon, ms] = await Promise.all([
|
||||
fetch(`${settlement}/api/v1/settlement/health`).then((r) => r.json()),
|
||||
fetch(`${settlement}/api/v1/settlement/office`).then((r) => r.json()),
|
||||
fetch(`${settlement}/api/v1/settlement/tokens/m2`).then((r) => r.json()),
|
||||
fetch(`${exchange}/api/v1/exchange/swap/monitor?limit=10`).then((r) => r.json()),
|
||||
loadMoneySupply(settlement),
|
||||
fetch(settlementApi('/health')).then((r) => r.json()),
|
||||
fetch(settlementApi('/office')).then((r) => r.json()),
|
||||
fetch(settlementApi('/tokens/m2')).then((r) => r.json()),
|
||||
fetch(exchangeApi('/swap/monitor?limit=10')).then((r) => r.json()),
|
||||
loadMoneySupply(),
|
||||
]);
|
||||
setHealth(h);
|
||||
setOffice(o);
|
||||
@@ -58,7 +55,7 @@ export function useCentralBank() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [settlement, exchange]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { DBIS_EXCHANGE_URL, SETTLEMENT_MIDDLEWARE_URL, type DexToken } from '../../config/dex';
|
||||
import { exchangeApi, settlementApi, type DexToken } from '../../config/dex';
|
||||
import type { MoneySupply } from '../central-bank/useCentralBank';
|
||||
|
||||
export type M2Token = DexToken & {
|
||||
@@ -17,19 +17,14 @@ export function useOffice24() {
|
||||
const [moneySupply, setMoneySupply] = useState<MoneySupply | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
const settlement = SETTLEMENT_MIDDLEWARE_URL.replace(/\/$/, '');
|
||||
const exchange = DBIS_EXCHANGE_URL.replace(/\/$/, '');
|
||||
|
||||
const refresh = useCallback(async () => {
|
||||
setLoading(true);
|
||||
try {
|
||||
const [o, t, h, ms] = await Promise.all([
|
||||
fetch(`${settlement}/api/v1/settlement/office`).then((r) => r.json()),
|
||||
fetch(`${settlement}/api/v1/settlement/tokens/m2`).then((r) => r.json()),
|
||||
fetch(`${exchange}/api/v1/exchange/health`).then((r) => r.json()),
|
||||
fetch(`${settlement}/api/v1/settlement/money-supply/public`).then((r) =>
|
||||
r.ok ? r.json() : null,
|
||||
),
|
||||
fetch(settlementApi('/office')).then((r) => r.json()),
|
||||
fetch(settlementApi('/tokens/m2')).then((r) => r.json()),
|
||||
fetch(exchangeApi('/health')).then((r) => r.json()),
|
||||
fetch(settlementApi('/money-supply/public')).then((r) => (r.ok ? r.json() : null)),
|
||||
]);
|
||||
setOffice(o);
|
||||
setTokens(Array.isArray(t.tokens) ? t.tokens : []);
|
||||
@@ -38,7 +33,7 @@ export function useOffice24() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [settlement, exchange]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
refresh();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import { useAccount, useSendTransaction } from 'wagmi';
|
||||
import {
|
||||
DBIS_EXCHANGE_URL,
|
||||
exchangeApi,
|
||||
DEFAULT_TOKENS,
|
||||
fetchExchangeTokens,
|
||||
parseAmountToWei,
|
||||
@@ -37,8 +37,6 @@ export function useDbisSwap() {
|
||||
const [loadAmount, setLoadAmount] = useState('');
|
||||
const [lastSettlement, setLastSettlement] = useState<Record<string, unknown> | null>(null);
|
||||
|
||||
const baseUrl = DBIS_EXCHANGE_URL.replace(/\/$/, '');
|
||||
|
||||
useEffect(() => {
|
||||
fetchExchangeTokens().then((list) => {
|
||||
setTokens(list);
|
||||
@@ -51,12 +49,12 @@ export function useDbisSwap() {
|
||||
if (!address) return;
|
||||
try {
|
||||
const q = new URLSearchParams({ wallet: address });
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/ledgers?${q}`);
|
||||
const res = await fetch(`${exchangeApi('/ledgers')}?${q}`);
|
||||
if (res.ok) setLedger(await res.json());
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
}, [address, baseUrl]);
|
||||
}, [address]);
|
||||
|
||||
const fetchQuote = useCallback(async () => {
|
||||
if (!amountIn) return;
|
||||
@@ -69,7 +67,7 @@ export function useDbisSwap() {
|
||||
tokenOut: tokenOut.address,
|
||||
amountIn: wei,
|
||||
});
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/quote?${q}`);
|
||||
const res = await fetch(`${exchangeApi('/quote')}?${q}`);
|
||||
if (!res.ok) throw new Error(await res.text());
|
||||
const quote = await res.json();
|
||||
setPlan({ amountOut: quote.amountOut ?? quote.expectedOutput });
|
||||
@@ -78,7 +76,7 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [amountIn, tokenIn, tokenOut, baseUrl]);
|
||||
}, [amountIn, tokenIn, tokenOut]);
|
||||
|
||||
const fetchPlan = useCallback(async () => {
|
||||
if (!amountIn || !address) return;
|
||||
@@ -86,7 +84,7 @@ export function useDbisSwap() {
|
||||
setError(null);
|
||||
try {
|
||||
const wei = parseAmountToWei(amountIn, tokenIn.decimals);
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/execute-plan`, {
|
||||
const res = await fetch(exchangeApi('/execute-plan'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -105,12 +103,12 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [amountIn, tokenIn, tokenOut, address, slippageBps, baseUrl]);
|
||||
}, [amountIn, tokenIn, tokenOut, address, slippageBps]);
|
||||
|
||||
const settleSwap = useCallback(
|
||||
async (hash: string) => {
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/swap/settle`, {
|
||||
const res = await fetch(exchangeApi('/swap/settle'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -127,7 +125,7 @@ export function useDbisSwap() {
|
||||
/* optional M2 audit */
|
||||
}
|
||||
},
|
||||
[baseUrl, amountIn, address, tokenIn, tokenOut],
|
||||
[amountIn, address, tokenIn, tokenOut],
|
||||
);
|
||||
|
||||
const executeSwap = useCallback(async () => {
|
||||
@@ -143,7 +141,7 @@ export function useDbisSwap() {
|
||||
data: plan.execution.encodedCalldata as `0x${string}`,
|
||||
});
|
||||
setTxHash(hash);
|
||||
await fetch(`${baseUrl}/api/v1/exchange/swap/record`, {
|
||||
await fetch(exchangeApi('/swap/record'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -162,14 +160,14 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [plan, address, sendTransactionAsync, fetchPlan, tokenIn, tokenOut, amountIn, baseUrl, settleSwap]);
|
||||
}, [plan, address, sendTransactionAsync, fetchPlan, tokenIn, tokenOut, amountIn, settleSwap]);
|
||||
|
||||
const loadM2Token = useCallback(async () => {
|
||||
if (!address || !loadAmount) return;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/token-load`, {
|
||||
const res = await fetch(exchangeApi('/token-load'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -191,14 +189,14 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [address, loadAmount, tokenOut, baseUrl, loadLedgers]);
|
||||
}, [address, loadAmount, tokenOut, loadLedgers]);
|
||||
|
||||
const internalTransfer = useCallback(async () => {
|
||||
if (!address || !transferTo || !transferAmount) return;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/transfer/internal`, {
|
||||
const res = await fetch(exchangeApi('/transfer/internal'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -218,14 +216,14 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [address, transferTo, transferAmount, tokenIn, baseUrl]);
|
||||
}, [address, transferTo, transferAmount, tokenIn]);
|
||||
|
||||
const externalTransfer = useCallback(async () => {
|
||||
if (!address || !transferTo || !transferAmount || !externalIban) return;
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/transfer/external`, {
|
||||
const res = await fetch(exchangeApi('/transfer/external'), {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
@@ -246,16 +244,16 @@ export function useDbisSwap() {
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
}, [address, transferTo, transferAmount, externalIban, tokenIn, baseUrl]);
|
||||
}, [address, transferTo, transferAmount, externalIban, tokenIn]);
|
||||
|
||||
const loadMonitor = useCallback(async () => {
|
||||
try {
|
||||
const res = await fetch(`${baseUrl}/api/v1/exchange/swap/monitor?limit=20`);
|
||||
const res = await fetch(`${exchangeApi('/swap/monitor')}?limit=20`);
|
||||
if (res.ok) setMonitor(await res.json());
|
||||
} catch {
|
||||
/* optional */
|
||||
}
|
||||
}, [baseUrl]);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
address,
|
||||
|
||||
Reference in New Issue
Block a user