Upload static/shared/js/page-functionality-bridge.js with huggingface_hub
Browse files
static/shared/js/page-functionality-bridge.js
CHANGED
|
@@ -14,12 +14,27 @@
|
|
| 14 |
help: '/api/max/help'
|
| 15 |
};
|
| 16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
function css() {
|
| 18 |
if (document.getElementById('max-provider-bridge-style')) return;
|
| 19 |
const style = document.createElement('style');
|
| 20 |
style.id = 'max-provider-bridge-style';
|
| 21 |
style.textContent = `
|
| 22 |
-
.max-provider-bridge{
|
| 23 |
.max-provider-bridge__head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;}
|
| 24 |
.max-provider-bridge__title{font-size:14px;font-weight:800;letter-spacing:.02em;display:flex;align-items:center;gap:8px;}
|
| 25 |
.max-provider-bridge__subtitle{font-size:11px;color:#64748b;margin-top:2px;}
|
|
@@ -34,7 +49,7 @@
|
|
| 34 |
.max-provider-bridge__links a{font-size:11px;font-weight:700;text-decoration:none;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:999px;padding:5px 9px;}
|
| 35 |
.max-provider-bridge__warn{font-size:11px;color:#92400e;background:#fffbeb;border:1px solid #fde68a;border-radius:10px;padding:8px 10px;margin-top:10px;}
|
| 36 |
@keyframes maxProviderPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.48;transform:scale(.82)}}
|
| 37 |
-
@media(max-width:900px){.max-provider-bridge__grid{grid-template-columns:repeat(2,minmax(0,1fr));}.max-provider-bridge{
|
| 38 |
@media(max-width:540px){.max-provider-bridge__grid{grid-template-columns:1fr}}
|
| 39 |
`;
|
| 40 |
document.head.appendChild(style);
|
|
@@ -44,7 +59,7 @@
|
|
| 44 |
const controller = new AbortController();
|
| 45 |
const timer = setTimeout(() => controller.abort(), 12000);
|
| 46 |
try {
|
| 47 |
-
const res = await fetch(url, { signal: controller.signal, headers: {
|
| 48 |
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
| 49 |
return await res.json();
|
| 50 |
} finally {
|
|
@@ -52,22 +67,11 @@
|
|
| 52 |
}
|
| 53 |
}
|
| 54 |
|
| 55 |
-
function findMount() {
|
| 56 |
-
return document.querySelector('[data-page-root], main, .main-content, .content, .container, #app, body');
|
| 57 |
-
}
|
| 58 |
-
|
| 59 |
-
function pageId() {
|
| 60 |
-
const parts = location.pathname.split('/').filter(Boolean);
|
| 61 |
-
return parts[0] || 'dashboard';
|
| 62 |
-
}
|
| 63 |
-
|
| 64 |
function render(state) {
|
| 65 |
css();
|
| 66 |
-
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
el.id = 'max-provider-bridge';
|
| 70 |
-
el.className = 'max-provider-bridge';
|
| 71 |
const providers = state.providers || {};
|
| 72 |
const resources = state.resources || {};
|
| 73 |
const market = state.market || {};
|
|
@@ -75,43 +79,54 @@
|
|
| 75 |
const kucoin = state.kucoin || {};
|
| 76 |
const prices = Array.isArray(market.items) ? market.items.filter(x => x && x.success) : [];
|
| 77 |
const bestPrice = prices[0];
|
| 78 |
-
const topSource = bestPrice
|
|
|
|
|
|
|
| 79 |
const fng = sentiment.fear_greed && sentiment.fear_greed.ok ? sentiment.fear_greed.data : null;
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
<div
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 85 |
</div>
|
| 86 |
-
<div class="max-provider-
|
| 87 |
-
</
|
| 88 |
-
<div class="max-provider-bridge__grid">
|
| 89 |
-
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Providers</div><div class="max-provider-bridge__value">${providers.healthy_count || 0}/${providers.probed_count || 0}</div></div>
|
| 90 |
-
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Registry</div><div class="max-provider-bridge__value">${((resources.summary || {}).comprehensive_resources || 0) + ((resources.summary || {}).unified_registry_entries || 0)}</div></div>
|
| 91 |
-
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Market sample</div><div class="max-provider-bridge__value small">${topSource}</div></div>
|
| 92 |
-
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Futures / Sentiment</div><div class="max-provider-bridge__value small">KuCoin: ${kucoin.validated ? 'validated' : 'not validated yet'}<br>F&G: ${fng ? `${fng.value} ${fng.classification || ''}` : 'pending'}</div></div>
|
| 93 |
-
</div>
|
| 94 |
-
<div class="max-provider-bridge__links">
|
| 95 |
-
<a href="/api/max/providers/status?include_slow=true" target="_blank">All provider health</a>
|
| 96 |
-
<a href="/api/max/fallback/plan" target="_blank">Fallback plan</a>
|
| 97 |
-
<a href="/api/max/pressure/status" target="_blank">Pressure status</a>
|
| 98 |
-
<a href="/api/max/resources/summary" target="_blank">Resource registry</a>
|
| 99 |
-
<a href="/api/max/market/snapshot" target="_blank">Market snapshot</a>
|
| 100 |
-
<a href="/api/max/trading/ohlcv/BTCUSDT" target="_blank">BTC OHLCV</a>
|
| 101 |
-
<a href="/api/max/trading/orderbook/BTCUSDT" target="_blank">BTC orderbook</a>
|
| 102 |
-
<a href="/api/max/futures/kucoin/validate/BTCUSDT" target="_blank">KuCoin futures</a>
|
| 103 |
-
<a href="/api/max/system/visual?symbol=BTC" target="_blank">System visual API</a>
|
| 104 |
-
<a href="/api/max/help" target="_blank">Max API help</a>
|
| 105 |
-
</div>
|
| 106 |
-
${providers.down_count ? `<div class="max-provider-bridge__warn">${providers.down_count} provider probe(s) failed on this check; fallbacks remain available through the chain.</div>` : ''}
|
| 107 |
`;
|
| 108 |
-
|
| 109 |
-
|
| 110 |
-
|
|
|
|
|
|
|
| 111 |
}
|
| 112 |
|
| 113 |
async function boot() {
|
| 114 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 115 |
const state = {};
|
| 116 |
const jobs = [
|
| 117 |
['providers', API.providers],
|
|
@@ -129,6 +144,14 @@
|
|
| 129 |
window.MAX_PROVIDER_BRIDGE_STATE = state;
|
| 130 |
}
|
| 131 |
|
| 132 |
-
|
| 133 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 134 |
})();
|
|
|
|
| 14 |
help: '/api/max/help'
|
| 15 |
};
|
| 16 |
|
| 17 |
+
function panel() {
|
| 18 |
+
return window.TopServicePanel;
|
| 19 |
+
}
|
| 20 |
+
|
| 21 |
+
function refreshSummary() {
|
| 22 |
+
const tsp = panel();
|
| 23 |
+
if (!tsp) return;
|
| 24 |
+
const parts = window._topServiceSummary || {};
|
| 25 |
+
tsp.setSummary(tsp.buildSummary([
|
| 26 |
+
`Page: ${tsp.pageId()}`,
|
| 27 |
+
parts.bridge,
|
| 28 |
+
parts.native
|
| 29 |
+
]));
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
function css() {
|
| 33 |
if (document.getElementById('max-provider-bridge-style')) return;
|
| 34 |
const style = document.createElement('style');
|
| 35 |
style.id = 'max-provider-bridge-style';
|
| 36 |
style.textContent = `
|
| 37 |
+
.max-provider-bridge{padding:16px;border:1px solid rgba(148,163,184,.28);border-radius:18px;background:linear-gradient(135deg,rgba(255,255,255,.90),rgba(240,249,255,.75));backdrop-filter:blur(14px);font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;color:#0f172a;}
|
| 38 |
.max-provider-bridge__head{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;}
|
| 39 |
.max-provider-bridge__title{font-size:14px;font-weight:800;letter-spacing:.02em;display:flex;align-items:center;gap:8px;}
|
| 40 |
.max-provider-bridge__subtitle{font-size:11px;color:#64748b;margin-top:2px;}
|
|
|
|
| 49 |
.max-provider-bridge__links a{font-size:11px;font-weight:700;text-decoration:none;color:#2563eb;background:#eff6ff;border:1px solid #bfdbfe;border-radius:999px;padding:5px 9px;}
|
| 50 |
.max-provider-bridge__warn{font-size:11px;color:#92400e;background:#fffbeb;border:1px solid #fde68a;border-radius:10px;padding:8px 10px;margin-top:10px;}
|
| 51 |
@keyframes maxProviderPulse{0%,100%{opacity:1;transform:scale(1)}50%{opacity:.48;transform:scale(.82)}}
|
| 52 |
+
@media(max-width:900px){.max-provider-bridge__grid{grid-template-columns:repeat(2,minmax(0,1fr));}.max-provider-bridge{padding:12px}}
|
| 53 |
@media(max-width:540px){.max-provider-bridge__grid{grid-template-columns:1fr}}
|
| 54 |
`;
|
| 55 |
document.head.appendChild(style);
|
|
|
|
| 59 |
const controller = new AbortController();
|
| 60 |
const timer = setTimeout(() => controller.abort(), 12000);
|
| 61 |
try {
|
| 62 |
+
const res = await fetch(url, { signal: controller.signal, headers: { Accept: 'application/json' } });
|
| 63 |
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
| 64 |
return await res.json();
|
| 65 |
} finally {
|
|
|
|
| 67 |
}
|
| 68 |
}
|
| 69 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 70 |
function render(state) {
|
| 71 |
css();
|
| 72 |
+
const tsp = panel();
|
| 73 |
+
if (!tsp || document.getElementById('max-provider-bridge-section')) return;
|
| 74 |
+
|
|
|
|
|
|
|
| 75 |
const providers = state.providers || {};
|
| 76 |
const resources = state.resources || {};
|
| 77 |
const market = state.market || {};
|
|
|
|
| 79 |
const kucoin = state.kucoin || {};
|
| 80 |
const prices = Array.isArray(market.items) ? market.items.filter(x => x && x.success) : [];
|
| 81 |
const bestPrice = prices[0];
|
| 82 |
+
const topSource = bestPrice
|
| 83 |
+
? `${bestPrice.symbol || 'BTC'} ${bestPrice.price ? '$' + Number(bestPrice.price).toLocaleString() : ''} · ${bestPrice.source || 'source'}`
|
| 84 |
+
: 'No live market response yet';
|
| 85 |
const fng = sentiment.fear_greed && sentiment.fear_greed.ok ? sentiment.fear_greed.data : null;
|
| 86 |
+
|
| 87 |
+
const html = `
|
| 88 |
+
<section id="max-provider-bridge" class="max-provider-bridge">
|
| 89 |
+
<div class="max-provider-bridge__head">
|
| 90 |
+
<div>
|
| 91 |
+
<div class="max-provider-bridge__title">⚡ Live Provider Bridge <span class="max-provider-bridge__pill"><span class="max-provider-bridge__dot"></span> functional layer</span></div>
|
| 92 |
+
<div class="max-provider-bridge__subtitle">Connected to the maximum-provider API layer. Page: <strong>${tsp.pageId()}</strong></div>
|
| 93 |
+
</div>
|
| 94 |
+
<div class="max-provider-bridge__pill">/api/max</div>
|
| 95 |
+
</div>
|
| 96 |
+
<div class="max-provider-bridge__grid">
|
| 97 |
+
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Providers</div><div class="max-provider-bridge__value">${providers.healthy_count || 0}/${providers.probed_count || 0}</div></div>
|
| 98 |
+
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Registry</div><div class="max-provider-bridge__value">${((resources.summary || {}).comprehensive_resources || 0) + ((resources.summary || {}).unified_registry_entries || 0)}</div></div>
|
| 99 |
+
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Market sample</div><div class="max-provider-bridge__value small">${topSource}</div></div>
|
| 100 |
+
<div class="max-provider-bridge__card"><div class="max-provider-bridge__label">Futures / Sentiment</div><div class="max-provider-bridge__value small">KuCoin: ${kucoin.validated ? 'validated' : 'not validated yet'}<br>F&G: ${fng ? `${fng.value} ${fng.classification || ''}` : 'pending'}</div></div>
|
| 101 |
+
</div>
|
| 102 |
+
<div class="max-provider-bridge__links">
|
| 103 |
+
<a href="/api/max/providers/status?include_slow=true" target="_blank" rel="noreferrer">All provider health</a>
|
| 104 |
+
<a href="/api/max/fallback/plan" target="_blank" rel="noreferrer">Fallback plan</a>
|
| 105 |
+
<a href="/api/max/pressure/status" target="_blank" rel="noreferrer">Pressure status</a>
|
| 106 |
+
<a href="/api/max/resources/summary" target="_blank" rel="noreferrer">Resource registry</a>
|
| 107 |
+
<a href="/api/max/market/snapshot" target="_blank" rel="noreferrer">Market snapshot</a>
|
| 108 |
+
<a href="/api/max/trading/ohlcv/BTCUSDT" target="_blank" rel="noreferrer">BTC OHLCV</a>
|
| 109 |
+
<a href="/api/max/trading/orderbook/BTCUSDT" target="_blank" rel="noreferrer">BTC orderbook</a>
|
| 110 |
+
<a href="/api/max/futures/kucoin/validate/BTCUSDT" target="_blank" rel="noreferrer">KuCoin futures</a>
|
| 111 |
+
<a href="/api/max/system/visual?symbol=BTC" target="_blank" rel="noreferrer">System visual API</a>
|
| 112 |
+
<a href="/api/max/help" target="_blank" rel="noreferrer">Max API help</a>
|
| 113 |
</div>
|
| 114 |
+
${providers.down_count ? `<div class="max-provider-bridge__warn">${providers.down_count} provider probe(s) failed on this check; fallbacks remain available through the chain.</div>` : ''}
|
| 115 |
+
</section>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 116 |
`;
|
| 117 |
+
|
| 118 |
+
tsp.mountSection('max-provider-bridge-section', '', html);
|
| 119 |
+
window._topServiceSummary = window._topServiceSummary || {};
|
| 120 |
+
window._topServiceSummary.bridge = `Providers ${providers.healthy_count || 0}/${providers.probed_count || 0}`;
|
| 121 |
+
refreshSummary();
|
| 122 |
}
|
| 123 |
|
| 124 |
async function boot() {
|
| 125 |
+
const tsp = panel();
|
| 126 |
+
if (!tsp || tsp.shouldSkip()) return;
|
| 127 |
+
|
| 128 |
+
tsp.ensure(`Page: ${tsp.pageId()} · Loading…`);
|
| 129 |
+
|
| 130 |
const state = {};
|
| 131 |
const jobs = [
|
| 132 |
['providers', API.providers],
|
|
|
|
| 144 |
window.MAX_PROVIDER_BRIDGE_STATE = state;
|
| 145 |
}
|
| 146 |
|
| 147 |
+
function start() {
|
| 148 |
+
if (!window.TopServicePanel) {
|
| 149 |
+
console.warn('TopServicePanel not loaded; bridge panel skipped');
|
| 150 |
+
return;
|
| 151 |
+
}
|
| 152 |
+
boot();
|
| 153 |
+
}
|
| 154 |
+
|
| 155 |
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
|
| 156 |
+
else start();
|
| 157 |
})();
|